Compare commits

..

126 Commits

Author SHA1 Message Date
goldsimon
21a1cf9c80 patch by Bostjan Meglic: fixed bug #35809: PPP GetMask(): Compiler warning on big endian, possible bug on little endian system 2012-03-12 16:37:44 +01:00
goldsimon
6486c4b1d7 fixed bug #35595: Impossible to send broadcast without a gateway (introduced when fixing bug# 33551) 2012-02-23 10:12:38 +01:00
goldsimon
5deeaa652a Removed IPv6 code slipped in while cherry picking: MEMP_NUM_SYS_TIMEOUT default value must not depend on LWIP_IPV6, tcp unit tests failed, slipif assigned netif->output_ip6 2012-02-23 07:58:59 +01:00
goldsimon
3db3811054 unit tests lwipopts.h: NO_SYS==1, disable netconn and sockets (not tests) -> lwipopts.h is now usable for unix unit test makefile, too 2012-02-22 22:42:20 +01:00
goldsimon
f8bafcb298 Minor: cosmetic source code layout changes 2012-02-22 22:42:16 +01:00
goldsimon
eb658da462 Fixed unit tests: adapted lwipopts.h and fixed test_tcp_new_counters_pcb() after adding snd_wnd_max to struct tcp_pcb. 2012-02-22 22:42:09 +01:00
goldsimon
d8b2bc2788 Added lwipopts.h file for unit tests 2012-02-22 22:42:02 +01:00
goldsimon
07af231f2b fixed pbuf leak when PPP session is aborted through pppSigHUP() (bug #35541: PPP Memory Leak) 2012-02-22 22:41:53 +01:00
goldsimon
8d04da8c6e fixed bug #35531: Impossible to send multicast without a gateway (introduced when fixing bug# 33551) 2012-02-22 22:41:45 +01:00
goldsimon
6b37e7ec74 Patch by Stéphane Lesage:
fixed bug #35536 SNMP: error too big response is malformed
2012-02-22 22:41:14 +01:00
goldsimon
8c5edcf564 fixed bug #35537: MEMP_NUM_* sanity checks should be disabled with MEMP_MEM_MALLOC==1 2012-02-22 22:40:55 +01:00
goldsimon
162432fe24 Correctly calculate the default value of MEMP_NUM_SYS_TIMEOUT as needed 2012-02-22 22:37:45 +01:00
goldsimon
13791ccff3 Fixed unused local variable warning (patch #7711) 2012-02-22 22:37:10 +01:00
goldsimon
aecc5db1be Removed unused variable in ip_debug_print() 2012-02-14 21:30:38 +01:00
goldsimon
d4b169a6de partly fixed bug #25882: TCP hangs on MSS > pcb->snd_wnd (by not creating segments bigger than half the window) 2012-02-12 14:19:43 +01:00
goldsimon
61588f9d90 tcp pcb: persist_cnt can be u8_t instead of u32_t (since it is compared against u8_t only) 2012-02-12 14:19:34 +01:00
goldsimon
63dbd8faed fixed bug #35435: No pcb state check before adding it to time-wait queue while closing 2012-02-12 13:51:59 +01:00
goldsimon
4d71f7270b fixed bug #35305: pcb may be freed too early on shutdown(WR) 2012-02-12 13:51:49 +01:00
goldsimon
593f75fc3b fixed bug #34636: FIN_WAIT_2 - Incorrect shutdown of TCP pcb: don't let PCBs time out from FIN_WAIT_2 if the RX side wasn't close (by either calling tcp_close or tcp_shutdown(RDWR)) 2012-02-12 13:51:07 +01:00
goldsimon
bec8cf9f38 Fixed my last chagne to pbuf_copy 2012-02-12 13:50:18 +01:00
goldsimon
b163197340 - fixed bug #35151: DHCP asserts on incoming option lengths;
- fixed wrong CHANGELOG of the last commit
2012-02-12 13:49:53 +01:00
goldsimon
be1dccd15e pbuf_copy(): moved the check for "p_to != NULL" to a better place. 2012-02-12 13:49:34 +01:00
goldsimon
83b46811f9 fixed bug #35291: NULL pointer in pbuf_copy 2012-02-12 13:48:57 +01:00
goldsimon
1d96195f47 implemented API functions to access so_options of IP pcbs (UDP, TCP, RAW) (fixes bug #35061) 2012-02-12 13:48:40 +01:00
goldsimon
5546e46c60 Added option CHECKSUM_GEN_ICMP 2012-02-12 13:33:43 +01:00
goldsimon
4bcb7accb8 Fixed some merge errors 2011-12-15 06:19:25 +01:00
goldsimon
5f4f07c193 Merged from trunk: fixed compilation of tcp_helper.c 2011-12-14 22:10:39 +01:00
goldsimon
f76488a841 Merged from trunk: tcp_abandon: call tcp_rst before freeing the pcb to prevent copying addresses and ports to local variables 2011-12-14 21:49:47 +01:00
goldsimon
ef0a44c62d Merged from trunk: use constants for 'offset' based on pbuf_layer instead of calculating it using fall-through 2011-12-14 21:48:51 +01:00
goldsimon
d3ee77e7b1 Merged from trunk: use a define to set/reset netif->addr_hint to prevent too many #ifdef's in the code 2011-12-14 21:48:06 +01:00
goldsimon
a91d8e7395 Merged from trunk: removed empty function autoip_init() (converted to an empty define) 2011-12-14 21:46:47 +01:00
Simon Goldschmidt
3306641708 bug #33634 ip_forward() have a faulty behaviour: Added pbuf flags to mark incoming packets as link-layer broadcast/multicast. Also added code to allow ip_forward() to forward non-broadcast packets to the input netif (set IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1). 2011-12-14 21:11:34 +01:00
Simon Goldschmidt
1ebd914cdc correctly prefix all functions with 'etharp_' (also static functions) 2011-12-14 21:06:13 +01:00
goldsimon
56207f2505 fixed bug #31177: tcp timers can corrupt tcp_active_pcbs in some cases 2011-12-14 19:58:49 +01:00
goldsimon
4c8e4fa003 fix for bug #34684 was wrong (netif for arp table entries was only set/reset with SNMP enabled) 2011-12-14 19:58:39 +01:00
goldsimon
c4f3b8818a fixed bug #34884: sys_msleep() body needs to be surrounded with '#ifndef sys_msleep' 2011-12-14 19:58:25 +01:00
goldsimon
f0b0a3760c fixed bug #34684: Clear the arp table cache when netif is brought down 2011-12-14 19:58:03 +01:00
goldsimon
b361533584 SEQ-comparing defines: cast parameters to u32_t for clarity 2011-12-14 19:57:01 +01:00
Ivan Delamer
40a16289f7 Use pppRecvWakeup only if PPP_INPROC_OWNTHREAD is defined.
Change-Id: Ie800289eb5f6a64d0be1d38eab7154d4aa473d57
2011-12-14 19:56:18 +01:00
Ivan Delamer
ec565c8a19 Conditional compilation in ppp.c according to PPP_ options.
Change-Id: I466ce2b0114c9428f5e21bd0a09bb221f40bfc3e
2011-12-14 19:54:40 +01:00
goldsimon
0b382a0d53 fixed bug #34638: Dead code in tcp_receive - pcb->dupacks 2011-12-14 19:54:20 +01:00
goldsimon
386a4b7079 - moved processing of refused_data to an own function (used from tcp_fasttmr and tcp_input);
- improved readability of tcp_slowtmr by using defines to access keepalive variables
2011-12-14 19:53:51 +01:00
goldsimon
3585cc1a70 fixed bug #34429: possible memory corruption with LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT set to 1 2011-12-14 19:46:57 +01:00
goldsimon
4790ebf282 SLIP netif: add support for multiple input strategies (threaded, polling, RX from ISR) 2011-12-14 19:46:43 +01:00
goldsimon
4ffbcbf62e added missing valid/set_invalid defines for NO_SYS 2011-12-14 19:46:27 +01:00
goldsimon
76e74b6635 removed the need to disable ARP_QUEUEING when LWIP_ARP is disabled an TCP_QUEUE_OOSEQ when LWIP_TCP is disabled 2011-12-14 19:46:01 +01:00
goldsimon
77f0305ef0 Fix default value of TCP_SNDLOWAT for small values of TCP_SND_BUF (broken with my 2nd-last commit) 2011-12-14 19:45:15 +01:00
Simon Goldschmidt
935144b3a3 fixed bug #34592: lwip_gethostbyname_r uses nonstandard error value, removed those unused (nonstandard?) error values from arch.h 2011-12-14 19:44:38 +01:00
Simon Goldschmidt
a148e33c42 fixed default values of TCP_SNDLOWAT and TCP_SNDQUEUELOWAT for small windows (bug #34176 select after non-blocking send times out) 2011-12-14 19:43:42 +01:00
Simon Goldschmidt
d96703bba3 fixed bug #34587: TCP_BUILD_MSS_OPTION doesn't consider netif->mtu, causes slow network 2011-12-14 19:43:25 +01:00
goldsimon
9621ccb712 fixed bug #34581 missing parentheses in udplite sockets code 2011-12-14 19:42:23 +01:00
goldsimon
21f39082b7 fixed bug #34580 fcntl() is missing in LWIP_COMPAT_SOCKETS 2011-12-14 19:42:06 +01:00
Simon Goldschmidt
0da2bd7f62 fixed bug #34569: shutdown(SHUT_WR) crashes netconn/socket api 2011-12-14 19:40:49 +01:00
Simon Goldschmidt
d8f090a759 fixed bug #34517 (persist timer is started although no zero window is received) by starting the persist timer when a zero window is received, not when we have more data queued for sending than fits into the window 2011-12-13 22:05:00 +01:00
Simon Goldschmidt
bd0a664446 fixed bug #34541: LWIP_U32_DIFF is unnecessarily complex: removed that define 2011-12-13 22:03:03 +01:00
Simon Goldschmidt
aafa00f3aa fixed bug #34540: compiler error when CORE_LOCKING is used and not all protocols are enabled 2011-12-13 21:49:19 +01:00
Simon Goldschmidt
dbbd161219 fixed bug #34534: Error in sending fragmented IP if MEM_ALIGNMENT > 4 2011-12-12 20:12:53 +01:00
Simon Goldschmidt
26f69123fd added unit test cases for seqno wraparound on fast-rexmit and rto-rexmit (unsent/unacked lists must be correctly sorted) 2011-12-12 20:12:20 +01:00
Simon Goldschmidt
de4a51e96e slightly rearranged freeing an acked segment to prevent keeping the reference too long 2011-12-12 20:12:07 +01:00
Simon Goldschmidt
a0bd27053d Added unit test case for persist timer / zero window probes 2011-12-12 20:11:02 +01:00
Simon Goldschmidt
56cee6b4d8 fixed bug #34426: tcp_zero_window_probe() transmits incorrect byte value when pcb->unacked != NULL 2011-12-11 19:54:43 +01:00
Simon Goldschmidt
277c7aa518 fixed bug #34447 LWIP_IP_ACCEPT_UDP_PORT(dst_port) wrong 2011-12-11 19:54:09 +01:00
Simon Goldschmidt
5cfef5bf48 Tried to fix bug #32417 ("TCP_OVERSIZE seems to have problems with (fast-)retransmission"): Reset pcb->unsent_oversize in 2 more places... 2011-12-11 19:46:21 +01:00
Simon Goldschmidt
ca6fd6015c Implemented limiting data on ooseq queue (task #9989) (define TCP_OOSEQ_MAX_BYTES / TCP_OOSEQ_MAX_PBUFS in lwipopts.h), added unit test for this new feature 2011-12-11 19:45:59 +01:00
Simon Goldschmidt
eff10f6458 fixed bug #28288: Data after FIN in oos queue 2011-12-11 19:45:29 +01:00
goldsimon
9c3a6b828f bug #34406 dhcp_option_hostname() can overflow the pbuf 2011-12-11 19:45:07 +01:00
Simon Goldschmidt
ba3567ea40 added unit tests for data-after-FIN 2011-12-11 19:44:56 +01:00
Simon Goldschmidt
513522d7c4 fixed unit tests (one TCP test failed, removed comma at the end of array initializers) 2011-12-11 19:44:43 +01:00
Simon Goldschmidt
5715469d26 fixed bug #34377 MEM_SIZE_F is not defined if MEM_LIBC_MALLOC==1 2011-12-11 19:44:01 +01:00
Simon Goldschmidt
140eb22cf0 fixed bug #33871: rejecting TCP_EVENT_RECV() for the last packet including FIN can lose data 2011-12-11 19:43:40 +01:00
Simon Goldschmidt
ac7c061406 Fixed tcp_accepted define (need brackets around the parameter) 2011-12-11 19:38:16 +01:00
Simon Goldschmidt
45a3f198e8 fixed bug #34355: nagle does not take snd_buf/snd_queuelen into account 2011-12-11 19:36:03 +01:00
Simon Goldschmidt
d5eb52868e Corrected fix for bug #34072 (UDP broadcast is received from wrong UDP pcb if udp port matches): pcbs bound to IPADDR_ANY did not receive broadcasts any more (bug #34294) 2011-12-11 19:35:43 +01:00
Simon Goldschmidt
3d48abb98d Implemented timeout on send (TCP only, bug #33820) 2011-12-11 19:30:05 +01:00
Simon Goldschmidt
223307fa38 fixed default value of TCP_SND_BUF to not violate the sanity checks in init.c 2011-12-11 19:29:39 +01:00
Simon Goldschmidt
c951ab8cee Converted runtime-sanity-checks into compile-time checks that can be disabled (since runtime checks can often not be seen on embedded targets) 2011-12-11 19:28:51 +01:00
goldsimon
81a49a437a fixed bug #34337 (possible NULL pointer in sys_check_timeouts) 2011-12-11 19:28:11 +01:00
Simon Goldschmidt
5460900b14 splitted ppp.h to an internal and external header file to get a clear separation of which functions an application or port may use (task #11281) 2011-12-11 19:24:16 +01:00
Simon Goldschmidt
2576a2e565 use pcb->mss instead of TCP_MSS for preallocate mss-sized pbufs (bug #34019) 2011-12-11 19:18:45 +01:00
Simon Goldschmidt
49369cc9ce Added a config option to randomize initial local TCP/UDP ports (so that different port ranges are used after a reboot; bug #33818; this one added tcp_init/udp_init functions again);
fixed a possible endless loop in tcp_new_port() if the number of active PCBs exceeds the number of available ports;
2011-12-11 19:18:09 +01:00
Simon Goldschmidt
fe66fa6540 Fixed typo: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN (as checked in init.c), not greater 2011-12-11 19:15:57 +01:00
Simon Goldschmidt
72e2d16f14 fixed bug #34072: UDP broadcast is received from wrong UDP pcb if udp port matches 2011-12-11 19:15:35 +01:00
Simon Goldschmidt
378bed8a03 DHCP uses LWIP_RAND() for xid's (bug #30302) 2011-12-11 18:50:36 +01:00
Simon Goldschmidt
9a1eeeea67 fixed bug #33952 PUSH flag in incoming packet is lost when packet is aggregated and sent to application 2011-12-11 18:49:50 +01:00
Simon Goldschmidt
68f8966f74 unit tests: correctly handle small PBUF_POOL_BUFSIZE settings, prevent NULL-pointer-deref. (ooseq test is still not running correctly...) 2011-12-11 18:49:31 +01:00
Simon Goldschmidt
e6a179ea32 netconn_alloc(): return on invalid protocol instead of initializing mbox size to 0 2011-12-11 18:49:07 +01:00
Simon Goldschmidt
adb2aeb10f fixed bug #31809 LWIP_EVENT_API in opts.h is inconsistent compared to other options 2011-12-11 18:47:23 +01:00
Simon Goldschmidt
a030b741a5 fixed bug #34111 RST for ACK to listening pcb has wrong seqno 2011-12-11 18:46:34 +01:00
goldsimon
6145af516b Fixed bogus IPH_V/HL and IPH_VHL_SET endianess dependency 2011-12-06 22:12:39 +01:00
Simon Goldschmidt
b1359f1c80 added netif remove callback (bug #32397) 2011-12-06 22:10:00 +01:00
goldsimon
7d254a542c fix automatically merged fix for bug #33956 (TCP netconns don't need NETCONNTYPE_GROUP without IPv6 support) 2011-12-06 22:09:24 +01:00
Simon Goldschmidt
422e7963de fixed bug #33956 Wrong error returned when calling accept() on UDP connections 2011-12-06 22:07:08 +01:00
Simon Goldschmidt
e2cdf0d39d fixed bug #34057 socklen_t should be a typedef 2011-12-06 22:06:25 +01:00
Simon Goldschmidt
2fe1af0d05 fixed bug #34112 Odd check in pbuf_alloced_custom (typo) 2011-12-06 22:05:54 +01:00
Simon Goldschmidt
ff85feb22d fixed bug #34122 dhcp: hostname can overflow 2011-12-06 22:05:15 +01:00
Simon Goldschmidt
be191148e0 fixed bug #34121 netif_add/netif_set_ipaddr fail on NULL ipaddr 2011-12-06 22:04:45 +01:00
Simon Goldschmidt
626131fb28 fixed bug #33962 TF_FIN not always set after FIN is sent. (This merely prevents nagle from not transmitting fast after closing.) 2011-12-06 22:04:01 +01:00
Simon Goldschmidt
d154f5c653 ETHARP_SUPPORT_VLAN: add support for an external VLAN filter function instead of only checking for one VLAN (define ETHARP_VLAN_CHECK_FN) 2011-12-06 22:01:15 +01:00
Simon Goldschmidt
38f619dd6f IPv4: splitted IPv4 header fields version/len and tos, made macros depend on BYTE_ORDER to prevent unnecessary calls to htons() 2011-12-06 21:57:56 +01:00
Simon Goldschmidt
5b899dd85b Prevent non-static function that is not declared in header file 2011-12-06 21:47:15 +01:00
Simon Goldschmidt
e7b9849a1a Fixed some C compiler warnings 2011-12-06 21:46:53 +01:00
Simon Goldschmidt
b1980b36b8 fixed bug #31084 (socket API returns always EMSGSIZE on non-blocking sockets if data size > send buffers) -> now lwip_send() sends as much as possible for non-blocking sockets and only returns EWOULDBLOCK if the buffers are full 2011-12-06 21:44:53 +01:00
Simon Goldschmidt
20833fdcc4 init.c: changed some checks from runtime to compiletime (had to adapt some defines in ip.h for that) 2011-12-06 21:42:55 +01:00
Simon Goldschmidt
1ac0c90ec4 forgot CHANGELOG: freeing ooseq pbufs when the pbuf pool is empty implemented for NO_SYS==1: when not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() at regular intervals from main level. 2011-12-06 21:40:03 +01:00
Simon Goldschmidt
e931086c3e freeing ooseq pbufs when the pbuf pool is empty implemented for NO_SYS==1: when not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() at regular intervals from main level. 2011-12-06 21:39:39 +01:00
Simon Goldschmidt
b65af6c572 ETHARP_STATE_STABLE_REREQUESTING: no need for member 'netif' in 'struct etharp_entry' if we re-request only from etharp_output() and use etharp_tmr() to reset the state of such entries to ETHARP_STATE_STABLE: that way, we also only send one ARP request per ARP_TMR_INTERVAL, but only if the entry is really still used. 2011-12-06 21:38:14 +01:00
Simon Goldschmidt
5983c1c5ff ETHARP_SUPPORT_STATIC_ENTRIES: don't need the member 'static_entry' on struct etharp_entry, we can use 'state' to mark them as static 2011-12-06 21:37:51 +01:00
Simon Goldschmidt
be412dc042 fixed bug #33551 (ARP entries may time out although in use) by sending an ARP request when an ARP entry is used in the last minute before it would time out. 2011-12-06 21:37:01 +01:00
Simon Goldschmidt
23dfcf7b8c Fixed bug #33802 tcpip: tcpip_callbackmsg_new sets msg->type to wrong type 2011-12-06 21:35:39 +01:00
goldsimon
e8b80b8ae9 Include opt.h so that LWIP_ERROR works correctly 2011-12-06 21:34:47 +01:00
goldsimon
a7f7762302 Fixed documentation after changing sys arch prototypes for 1.4.0 2011-12-06 21:32:38 +01:00
goldsimon
859fd87600 Slightly reorderd fields of struct tcp_pcb to plug holes introduced by member alignment (to reduce RAM usage) 2011-12-06 21:30:45 +01:00
goldsimon
211b8be07d fixed bug #31723 (tcp_kill_prio() kills pcbs with the same prio) by updating its documentation only. 2011-12-06 21:29:33 +01:00
goldsimon
22ee104a04 fixed bug #33545: With MEM_USE_POOLS==1, mem_malloc can return an unaligned pointer. 2011-12-06 21:28:36 +01:00
goldsimon
49e16fcbe9 Fixed bug #33544 (warning in mem.c in lwip 1.4.0 with NO_SYS=1) 2011-12-05 21:23:56 +01:00
goldsimon
1b79ac1160 Added some more asserts to check that pcb->state != LISTEN 2011-12-05 21:21:27 +01:00
goldsimon
f9e286ff67 Cleaned up usage of sys.h a bit 2011-12-05 21:19:38 +01:00
goldsimon
d798abcb91 Provide a default for SNMP_GET_SYSUPTIME() based on sys_now() 2011-12-05 21:17:57 +01:00
goldsimon
5c05d427b0 use const char for name pointers in display functions 2011-12-05 21:17:09 +01:00
goldsimon
a45b1bad35 use const char for name pointers in display functions 2011-12-05 21:16:24 +01:00
goldsimon
88bf9b2380 Removed unused static function 2011-12-05 21:15:32 +01:00
goldsimon
717b2dab59 Moved static variable from inside the function to global scope 2011-12-05 21:15:00 +01:00
goldsimon
8d74559f72 Moved common call to pbuf_header outside the switch() 2011-12-05 21:13:05 +01:00
goldsimon
59513b41e5 Restructured the code a bit to help my dump compiler not creating a jump table in ROM 2011-12-05 21:10:22 +01:00
goldsimon
fe2003124a - 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-12-05 21:08:17 +01:00
goldsimon
8b06c61a70 fixed bug #33398 (pointless conversion when checking TCP port range) 2011-12-05 20:58:51 +01:00
339 changed files with 32178 additions and 88079 deletions

4
.gitattributes vendored
View File

@@ -1,4 +0,0 @@
# These files are text and should be normalized
*.txt text
*.c text
*.h text

18
.gitignore vendored
View File

@@ -1,18 +0,0 @@
*.o
*.a
/doc/doxygen/output/html
/src/apps/snmp/LwipMibCompiler/CCodeGeneration/bin/
/src/apps/snmp/LwipMibCompiler/CCodeGeneration/obj/
/src/apps/snmp/LwipMibCompiler/LwipMibCompiler/bin/
/src/apps/snmp/LwipMibCompiler/LwipMibCompiler/obj/
/src/apps/snmp/LwipMibCompiler/MibViewer/bin/
/src/apps/snmp/LwipMibCompiler/MibViewer/obj/
/src/apps/snmp/LwipMibCompiler/LwipSnmpCodeGeneration/bin/
/src/apps/snmp/LwipMibCompiler/LwipSnmpCodeGeneration/obj/
/src/apps/snmp/LwipMibCompiler/SharpSnmpLib/bin/
/src/apps/snmp/LwipMibCompiler/SharpSnmpLib/obj/
/src/apps/snmp/LwipMibCompiler/LwipMibCompiler.userprefs
/src/apps/snmp/LwipMibCompiler/*.suo
/test/fuzz/output
/test/fuzz/lwip_fuzz
/test/fuzz/.depend

1208
CHANGELOG

File diff suppressed because it is too large Load Diff

1
FILES
View File

@@ -1,5 +1,4 @@
src/ - The source code for the lwIP TCP/IP stack.
doc/ - The documentation for lwIP.
test/ - Some code to test whether the sources do what they should.
See also the FILES file in each subdirectory.

65
README
View File

@@ -10,41 +10,28 @@ while still having a full scale TCP. This making lwIP suitable for use
in embedded systems with tens of kilobytes of free RAM and room for
around 40 kilobytes of code ROM.
FEATURES
* IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over
multiple network interfaces
* IP (Internet Protocol) including packet forwarding over multiple network
interfaces
* ICMP (Internet Control Message Protocol) for network maintenance and debugging
* IGMP (Internet Group Management Protocol) for multicast traffic management
* MLD (Multicast listener discovery for IPv6). Aims to be compliant with
RFC 2710. No support for MLDv2
* ND (Neighbor discovery and stateless address autoconfiguration for IPv6).
Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862
(Address autoconfiguration)
* UDP (User Datagram Protocol) including experimental UDP-lite extensions
* TCP (Transmission Control Protocol) with congestion control, RTT estimation
and fast recovery/fast retransmit
* raw/native API for enhanced performance
* Specialized raw/native API for enhanced performance
* Optional Berkeley-like socket API
* DNS (Domain names resolver)
APPLICATIONS
* HTTP server with SSI and CGI
* SNMPv2c agent with MIB compiler (Simple Network Management Protocol)
* SNTP (Simple network time protocol)
* NetBIOS name service responder
* MDNS (Multicast DNS) responder
* iPerf server implementation
* SNMP (Simple Network Management Protocol)
* DHCP (Dynamic Host Configuration Protocol)
* AUTOIP (for IPv4, conform with RFC 3927)
* PPP (Point-to-Point Protocol)
* ARP (Address Resolution Protocol) for Ethernet
LICENSE
lwIP is freely available under a BSD license.
DEVELOPMENT
lwIP has grown into an excellent TCP/IP stack for embedded devices,
@@ -53,34 +40,38 @@ and additions to the stack to further increase its usefulness.
Development of lwIP is hosted on Savannah, a central point for
software development, maintenance and distribution. Everyone can
help improve lwIP by use of Savannah's interface, Git and the
help improve lwIP by use of Savannah's interface, CVS and the
mailing list. A core team of developers will commit changes to the
Git source tree.
CVS source tree.
The lwIP TCP/IP stack is maintained in the 'lwip' Git module and
contributions (such as platform ports) are in the 'contrib' Git module.
The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and
contributions (such as platform ports) are in the 'contrib' module.
See doc/savannah.txt for details on Git server access for users and
See doc/savannah.txt for details on CVS server access for users and
developers.
The current Git trees are web-browsable:
http://git.savannah.gnu.org/cgit/lwip.git
http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git
Last night's CVS tar ball can be downloaded from:
http://savannah.gnu.org/cvs.backups/lwip.tar.gz [CHANGED - NEEDS FIXING]
The current CVS trees are web-browsable:
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/
Submit patches and bugs via the lwIP project page:
http://savannah.nongnu.org/projects/lwip/
Continuous integration builds (GCC, clang):
https://travis-ci.org/yarrick/lwip-merged
DOCUMENTATION
Self documentation of the source code is regularly extracted from the current
Git sources and is available from this web page:
The original out-dated homepage of lwIP and Adam Dunkels' papers on
lwIP are at the official lwIP home page:
http://www.sics.se/~adam/lwip/
Self documentation of the source code is regularly extracted from the
current CVS sources and is available from this web page:
http://www.nongnu.org/lwip/
There is now a constantly growing wiki about lwIP at
There is now a constantly growin wiki about lwIP at
http://lwip.wikia.com/wiki/LwIP_Wiki
Also, there are mailing lists you can subscribe at
@@ -89,12 +80,10 @@ plus searchable archives:
http://lists.nongnu.org/archive/html/lwip-users/
http://lists.nongnu.org/archive/html/lwip-devel/
lwIP was originally written by Adam Dunkels:
http://dunkels.com/adam/
Reading Adam's papers, the files in docs/, browsing the source code
documentation and browsing the mailing list archives is a good way to
become familiar with the design of lwIP.
Adam Dunkels <adam@sics.se>
Leon Woestenberg <leon.woestenberg@gmx.net>

View File

@@ -4,101 +4,10 @@ application written for an older version of lwIP to correctly work
with newer versions.
(git master)
(CVS HEAD)
* [Enter new changes just after this line - do not remove this line]
(2.0.1)
++ Application changes:
* UDP does NOT receive multicast traffic from ALL netifs on an UDP PCB bound to a specific
netif any more. Users need to bind to IP_ADDR_ANY to receive multicast traffic and compare
ip_current_netif() to the desired netif for every packet.
See bug #49662 for an explanation.
(2.0.0)
++ Application changes:
* Changed netif "up" flag handling to be an administrative flag (as opposed to the previous meaning of
"ip4-address-valid", a netif will now not be used for transmission if not up) -> even a DHCP netif
has to be set "up" before starting the DHCP client
* Added IPv6 support (dual-stack or IPv4/IPv6 only)
* Changed ip_addr_t to be a union in dual-stack mode (use ip4_addr_t where referring to IPv4 only).
* Major rewrite of SNMP (added MIB parser that creates code stubs for custom MIBs);
supports SNMPv2c (experimental v3 support)
* Moved some core applications from contrib repository to src/apps (and include/lwip/apps)
+++ Raw API:
* Changed TCP listen backlog: removed tcp_accepted(), added the function pair tcp_backlog_delayed()/
tcp_backlog_accepted() to explicitly delay backlog handling on a connection pcb
+++ Socket API:
* Added an implementation for posix sendmsg()
* Added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram
++ Port changes
+++ new files:
* MANY new and moved files!
* Added src/Filelists.mk for use in Makefile projects
* Continued moving stack-internal parts from abc.h to abc_priv.h in sub-folder "priv"
to let abc.h only contain the actual application programmer's API
+++ sys layer:
* Made LWIP_TCPIP_CORE_LOCKING==1 the default as it usually performs better than
the traditional message passing (although with LWIP_COMPAT_MUTEX you are still
open to priority inversion, so this is not recommended any more)
* Added LWIP_NETCONN_SEM_PER_THREAD to use one "op_completed" semaphore per thread
instead of using one per netconn (these semaphores are used even with core locking
enabled as some longer lasting functions like big writes still need to delay)
* Added generalized abstraction for itoa(), strnicmp(), stricmp() and strnstr()
in def.h (to be overridden in cc.h) instead of config
options for netbiosns, httpd, dns, etc. ...
* New abstraction for hton* and ntoh* functions in def.h.
To override them, use the following in cc.h:
#define lwip_htons(x) <your_htons>
#define lwip_htonl(x) <your_htonl>
+++ new options:
* TODO
+++ new pools:
* Added LWIP_MEMPOOL_* (declare/init/alloc/free) to declare private memp pools
that share memp.c code but do not have to be made global via lwippools.h
* Added pools for IPv6, MPU_COMPATIBLE, dns-api, netif-api, etc.
* added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when a memp pool was empty and an item
is now available
* Signature of LWIP_HOOK_VLAN_SET macro was changed
* LWIP_DECLARE_MEMORY_ALIGNED() may be used to declare aligned memory buffers (mem/memp)
or to move buffers to dedicated memory using compiler attributes
* Standard C headers are used to define sized types and printf formatters
(disable by setting LWIP_NO_STDINT_H=1 or LWIP_NO_INTTYPES_H=1 if your compiler
does not support these)
++ Major bugfixes/improvements
* Added IPv6 support (dual-stack or IPv4/IPv6 only)
* Major rewrite of PPP (incl. keep-up with apache pppd)
see doc/ppp.txt for an upgrading how-to
* Major rewrite of SNMP (incl. MIB parser)
* Fixed timing issues that might have lead to losing a DHCP lease
* Made rx processing path more robust against crafted errors
* TCP window scaling support
* modification of api modules to support FreeRTOS-MPU (don't pass stack-pointers to other threads)
* made DNS client more robust
* support PBUF_REF for RX packets
* LWIP_NETCONN_FULLDUPLEX allows netconn/sockets to be used for reading/writing from separate
threads each (needs LWIP_NETCONN_SEM_PER_THREAD)
* Moved and reordered stats (mainly memp/mib2)
(1.4.0)
++ Application changes:
* Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for

View File

@@ -1,9 +1,6 @@
doxygen/ - Configuration files and scripts to create the lwIP doxygen source
documentation (found at http://www.nongnu.org/lwip/)
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.
ppp.txt - Documentation of the PPP interface for lwIP.

View File

@@ -1,117 +0,0 @@
void eth_mac_irq()
{
/* Service MAC IRQ here */
/* Allocate pbuf from pool (avoid using heap in interrupts) */
struct pbuf* p = pbuf_alloc(PBUF_RAW, eth_data_count, PBUF_POOL);
if(p != NULL) {
/* Copy ethernet frame into pbuf */
pbuf_take(p, eth_data, eth_data_count);
/* Put in a queue which is processed in main loop */
if(!queue_try_put(&queue, p)) {
/* queue is full -> packet loss */
pbuf_free(p);
}
}
}
static err_t netif_output(struct netif *netif, struct pbuf *p)
{
LINK_STATS_INC(link.xmit);
/* Update SNMP stats (only if you use SNMP) */
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
int unicast = ((p->payload[0] & 0x01) == 0);
if (unicast) {
MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
} else {
MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
}
lock_interrupts();
pbuf_copy_partial(p, mac_send_buffer, p->tot_len, 0);
/* Start MAC transmit here */
unlock_interrupts();
return ERR_OK;
}
static void netif_status_callback(struct netif *netif)
{
printf("netif status changed %s\n", ip4addr_ntoa(netif_ip4_addr(netif)));
}
static err_t netif_init(struct netif *netif)
{
netif->linkoutput = netif_output;
netif->output = etharp_output;
netif->output_ip6 = ethip6_output;
netif->mtu = ETHERNET_MTU;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6;
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 100000000);
SMEMCPY(netif->hwaddr, your_mac_address_goes_here, sizeof(netif->hwaddr));
netif->hwaddr_len = sizeof(netif->hwaddr);
return ERR_OK;
}
void main(void)
{
struct netif netif;
lwip_init();
netif_add(&netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY, NULL, netif_init, netif_input);
netif.name[0] = 'e';
netif.name[1] = '0';
netif_create_ip6_linklocal_address(&netif, 1);
netif.ip6_autoconfig_enabled = 1;
netif_set_status_callback(&netif, netif_status_callback);
netif_set_default(&netif);
netif_set_up(&netif);
/* Start DHCP and HTTPD */
dhcp_init();
httpd_init();
while(1) {
/* Check link state, e.g. via MDIO communication with PHY */
if(link_state_changed()) {
if(link_is_up()) {
netif_set_link_up(&netif);
} else {
netif_set_link_down(&netif);
}
}
/* Check for received frames, feed them to lwIP */
lock_interrupts();
struct pbuf* p = queue_try_get(&queue);
unlock_interrupts();
if(p != NULL) {
LINK_STATS_INC(link.recv);
/* Update SNMP stats (only if you use SNMP) */
MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
int unicast = ((p->payload[0] & 0x01) == 0);
if (unicast) {
MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
} else {
MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
}
if(netif.input(p, &netif) != ERR_OK) {
pbuf_free(p);
}
}
/* Cyclic lwIP timers check */
sys_check_timeouts();
/* your application goes here */
}
}

View File

@@ -34,25 +34,30 @@ features of Savannah help us not lose users' input.
2.3 Bug reports and patches:
1. Make sure you are reporting bugs or send patches against the latest
sources. (From the latest release and/or the current Git sources.)
sources. (From the latest release and/or the current CVS sources.)
2. If you think you found a bug make sure it's not already filed in the
bugtracker at Savannah.
3. If you have a fix put the patch on Savannah. If it is a patch that affects
both core and arch specific stuff please separate them so that the core can
be applied separately while leaving the other patch 'open'. The preferred way
be applied separately while leaving the other patch 'open'. The prefered way
is to NOT touch archs you can't test and let maintainers take care of them.
This is a good way to see if they are used at all - the same goes for unix
netifs except tapif.
4. Do not file a bug and post a fix to it to the patch area. Either a bug report
or a patch will be enough.
If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area.
5. Patches should be specific to a single change or to related changes. Do not mix bugfixes with spelling and other
trivial fixes unless the bugfix is trivial too. Do not reorganize code and rename identifiers in the same patch you
change behaviour if not necessary. A patch is easier to read and understand if it's to the point and short than
5. Trivial patches (compiler warning, indentation and spelling fixes or anything obvious which takes a line or two)
can go to the lwip-users list. This is still the fastest way of interaction and the list is not so crowded
as to allow for loss of fixes. Putting bugs on Savannah and subsequently closing them is too much an overhead
for reporting a compiler warning fix.
6. Patches should be specific to a single change or to related changes.Do not mix bugfixes with spelling and other
trivial fixes unless the bugfix is trivial too.Do not reorganize code and rename identifiers in the same patch you
change behaviour if not necessary.A patch is easier to read and understand if it's to the point and short than
if it's not to the point and long :) so the chances for it to be applied are greater.
2.4 Platform porters:
1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and
you think it could benefit others[1] you might want discuss this on the mailing list. You
can also ask for Git access to submit and maintain your port in the contrib Git module.
can also ask for CVS access to submit and maintain your port in the contrib CVS module.

View File

@@ -1 +0,0 @@
doxygen lwip.Doxyfile

View File

@@ -1,3 +0,0 @@
#!/bin/sh
doxygen lwip.Doxyfile

File diff suppressed because it is too large Load Diff

View File

@@ -1,132 +0,0 @@
/**
* @defgroup lwip lwIP
*
* @defgroup infrastructure Infrastructure
*
* @defgroup callbackstyle_api Callback-style APIs
* Non thread-safe APIs, callback style for maximum performance and minimum
* memory footprint.
*
* @defgroup sequential_api Sequential-style APIs
* Sequential-style APIs, blocking functions. More overhead, but can be called
* from any thread except TCPIP thread.
*
* @defgroup addons Addons
*
* @defgroup apps Applications
*/
/**
* @mainpage Overview
* @verbinclude "README"
*/
/**
* @page upgrading Upgrading
* @verbinclude "UPGRADING"
*/
/**
* @page changelog Changelog
* @verbinclude "CHANGELOG"
*/
/**
* @page contrib How to contribute to lwIP
* @verbinclude "contrib.txt"
*/
/**
* @page pitfalls Common pitfalls
*
* Multiple Execution Contexts in lwIP code
* ========================================
*
* The most common source of lwIP problems is to have multiple execution contexts
* inside the lwIP code.
*
* lwIP can be used in two basic modes: @ref lwip_nosys (no OS/RTOS
* running on target system) or @ref lwip_os (there is an OS running
* on the target system).
*
* Mainloop Mode
* -------------
* In mainloop mode, only @ref callbackstyle_api can be used.
* The user has two possibilities to ensure there is only one
* exection context at a time in lwIP:
*
* 1) Deliver RX ethernet packets directly in interrupt context to lwIP
* by calling netif->input directly in interrupt. This implies all lwIP
* callback functions are called in IRQ context, which may cause further
* problems in application code: IRQ is blocked for a long time, multiple
* execution contexts in application code etc. When the application wants
* to call lwIP, it only needs to disable interrupts during the call.
* If timers are involved, even more locking code is needed to lock out
* timer IRQ and ethernet IRQ from each other, assuming these may be nested.
*
* 2) Run lwIP in a mainloop. There is example code here: @ref lwip_nosys.
* lwIP is _ONLY_ called from mainloop callstacks here. The ethernet IRQ
* has to put received telegrams into a queue which is polled in the
* mainloop. Ensure lwIP is _NEVER_ called from an interrupt, e.g.
* some SPI IRQ wants to forward data to udp_send() or tcp_write()!
*
* OS Mode
* -------
* In OS mode, @ref callbackstyle_api AND @ref sequential_api can be used.
* @ref sequential_api are designed to be called from threads other than
* the TCPIP thread, so there is nothing to consider here.
* But @ref callbackstyle_api functions must _ONLY_ be called from
* TCPIP thread. It is a common error to call these from other threads
* or from IRQ contexts. Ethernet RX needs to deliver incoming packets
* in the correct way by sending a message to TCPIP thread, this is
* implemented in tcpip_input().
* Again, ensure lwIP is _NEVER_ called from an interrupt, e.g.
* some SPI IRQ wants to forward data to udp_send() or tcp_write()!
*
* 1) tcpip_callback() can be used get called back from TCPIP thread,
* it is safe to call any @ref callbackstyle_api from there.
*
* 2) Use @ref LWIP_TCPIP_CORE_LOCKING. All @ref callbackstyle_api
* functions can be called when lwIP core lock is aquired, see
* @ref LOCK_TCPIP_CORE() and @ref UNLOCK_TCPIP_CORE().
* These macros cannot be used in an interrupt context!
* Note the OS must correctly handle priority inversion for this.
*/
/**
* @page bugs Reporting bugs
* Please report bugs in the lwIP bug tracker at savannah.\n
* BEFORE submitting, please check if the bug has already been reported!\n
* https://savannah.nongnu.org/bugs/?group=lwip
*/
/**
* @defgroup lwip_nosys Mainloop mode ("NO_SYS")
* @ingroup lwip
* Use this mode if you do not run an OS on your system. \#define NO_SYS to 1.
* Feed incoming packets to netif->input(pbuf, netif) function from mainloop,
* *not* *from* *interrupt* *context*. You can allocate a @ref pbuf in interrupt
* context and put them into a queue which is processed from mainloop.\n
* Call sys_check_timeouts() periodically in the mainloop.\n
* Porting: implement all functions in @ref sys_time, @ref sys_prot and
* @ref compiler_abstraction.\n
* You can only use @ref callbackstyle_api in this mode.\n
* Sample code:\n
* @include NO_SYS_SampleCode.c
*/
/**
* @defgroup lwip_os OS mode (TCPIP thread)
* @ingroup lwip
* Use this mode if you run an OS on your system. It is recommended to
* use an RTOS that correctly handles priority inversion and
* to use @ref LWIP_TCPIP_CORE_LOCKING.\n
* Porting: implement all functions in @ref sys_layer.\n
* You can use @ref callbackstyle_api together with @ref tcpip_callback,
* and all @ref sequential_api.
*/
/**
* @page raw_api lwIP API
* @verbinclude "rawapi.txt"
*/

View File

@@ -1,10 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Redirection</title>
<meta http-equiv="refresh" content="0; url=html/index.html" />
</head>
<body>
<a href="html/index.html">index.html</a>
</body>
</html>

View File

@@ -1,113 +0,0 @@
Multicast DNS for lwIP
Author: Erik Ekman
Note! The MDNS responder does not have all features required by the standards.
See notes in src/apps/mdns/mdns.c for what is left. It is however usable in normal
cases - but watch out if many devices on the same network try to use the same
host/service instance names.
How to enable:
==============
MDNS support does not depend on DNS.
MDNS supports using IPv4 only, v6 only, or v4+v6.
To enable MDNS responder, set
LWIP_MDNS_RESPONDER = 1
in lwipopts.h and add src/apps/mdns/mdns.c to your list of files to build.
The max number of services supported per netif is defined by MDNS_MAX_SERVICES,
default is 1.
Increase MEMP_NUM_UDP_PCB by 1. MDNS needs one PCB.
Increase LWIP_NUM_NETIF_CLIENT_DATA by 1 (MDNS needs one entry on netif).
MDNS with IPv4 requires LWIP_IGMP = 1, and preferably LWIP_AUTOIP = 1.
MDNS with IPv6 requires LWIP_IPV6_MLD = 1, and that a link-local address is
generated.
The MDNS code puts its structs on the stack where suitable to reduce dynamic
memory allocation. It may use up to 1kB of stack.
MDNS needs a strncasecmp() implementation. If you have one, define
LWIP_MDNS_STRNCASECMP to it. Otherwise the code will provide an implementation
for you.
How to use:
===========
Call mdns_resp_init() during system initialization.
This opens UDP sockets on port 5353 for IPv4 and IPv6.
To start responding on a netif, run
mdns_resp_add_netif(struct netif *netif, char *hostname, u32_t dns_ttl)
The hostname will be copied. If this returns successfully, the netif will join
the multicast groups and any MDNS/legacy DNS requests sent unicast or multicast
to port 5353 will be handled:
- <hostname>.local type A, AAAA or ANY returns relevant IP addresses
- Reverse lookups (PTR in-addr.arpa, ip6.arpa) of netif addresses
returns <hostname>.local
Answers will use the supplied TTL (in seconds)
MDNS allows UTF-8 names, but it is recommended to stay within ASCII,
since the default case-insensitive comparison assumes this.
It is recommended to call this function after an IPv4 address has been set,
since there is currently no check if the v4 address is valid.
Call mdns_resp_netif_settings_changed() every time the IP address
on the netif has changed.
To stop responding on a netif, run
mdns_resp_remove_netif(struct netif *netif)
Adding services:
================
The netif first needs to be registered. Then run
mdns_resp_add_service(struct netif *netif, char *name, char *service,
u16_t proto, u16_t port, u32_t dns_ttl,
service_get_txt_fn_t txt_fn, void *txt_userdata);
The name and service pointers will be copied. Name refers to the name of the
service instance, and service is the type of service, like _http
proto can be DNSSD_PROTO_UDP or DNSSD_PROTO_TCP which represent _udp and _tcp.
If this call returns successfully, the following queries will be answered:
- _services._dns-sd._udp.local type PTR returns <service>.<proto>.local
- <service>.<proto>.local type PTR returns <name>.<service>.<proto>.local
- <name>.<service>.<proto>.local type SRV returns hostname and port of service
- <name>.<service>.<proto>.local type TXT builds text strings by calling txt_fn
with the supplied userdata. The callback adds strings to the reply by calling
mdns_resp_add_service_txtitem(struct mdns_service *service, char *txt,
int txt_len). Example callback method:
static void srv_txt(struct mdns_service *service, void *txt_userdata)
{
res = mdns_resp_add_service_txtitem(service, "path=/", 6);
LWIP_ERROR("mdns add service txt failed\n", (res == ERR_OK), return);
}
Since a hostname struct is used for TXT storage each single item can be max
63 bytes long, and the total max length (including length bytes for each
item) is 255 bytes.
If your device runs a webserver on port 80, an example call might be:
mdns_resp_add_service(netif, "myweb", "_http"
DNSSD_PROTO_TCP, 80, 3600, srv_txt, NULL);
which will publish myweb._http._tcp.local for any hosts looking for web servers,
and point them to <hostname>.local:80
Relevant information will be sent as additional records to reduce number of
requests required from a client.
Removing services is currently not supported. Services are removed when the
netif is removed.

View File

@@ -1,162 +0,0 @@
MQTT client for lwIP
Author: Erik Andersson
Details of the MQTT protocol can be found at:
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
-----------------------------------------------------------------
1. Initial steps, reserve memory and make connection to server:
1.1: Provide storage
Static allocation:
mqtt_client_t static_client;
example_do_connect(&static_client);
Dynamic allocation:
mqtt_client_t *client = mqtt_client_new();
if(client != NULL) {
example_do_connect(&client);
}
1.2: Establish Connection with server
void example_do_connect(mqtt_client_t *client)
{
struct mqtt_connect_client_info_t ci;
err_t err;
/* Setup an empty client info structure */
memset(&ci, 0, sizeof(ci));
/* Minimal amount of information required is client identifier, so set it here */
ci.client_id = "lwip_test";
/* Initiate client and connect to server, if this fails immediately an error code is returned
otherwise mqtt_connection_cb will be called with connection result after attempting
to establish a connection with the server.
For now MQTT version 3.1.1 is always used */
err = mqtt_client_connect(client, ip_addr, MQTT_PORT, mqtt_connection_cb, 0, &ci);
/* For now just print the result code if something goes wrong
if(err != ERR_OK) {
printf("mqtt_connect return %d\n", err);
}
}
Connection to server can also be probed by calling mqtt_client_is_connected(client)
-----------------------------------------------------------------
2. Implementing the connection status callback
static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
{
err_t err;
if(status == MQTT_CONNECT_ACCEPTED) {
printf("mqtt_connection_cb: Successfully connected\n");
/* Setup callback for incoming publish requests */
mqtt_set_inpub_callback(client, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, arg);
/* Subscribe to a topic named "subtopic" with QoS level 1, call mqtt_sub_request_cb with result */
err = mqtt_subscribe(client, "subtopic", 1, mqtt_sub_request_cb, arg);
if(err != ERR_OK) {
printf("mqtt_subscribe return: %d\n", err);
}
} else {
printf("mqtt_connection_cb: Disconnected, reason: %d\n", status);
/* Its more nice to be connected, so try to reconnect */
example_do_connect(client);
}
}
static void mqtt_sub_request_cb(void *arg, err_t result)
{
/* Just print the result code here for simplicity,
normal behaviour would be to take some action if subscribe fails like
notifying user, retry subscribe or disconnect from server */
printf("Subscribe result: %d\n", result);
}
-----------------------------------------------------------------
3. Implementing callbacks for incoming publish and data
/* The idea is to demultiplex topic and create some reference to be used in data callbacks
Example here uses a global variable, better would be to use a member in arg
If RAM and CPU budget allows it, the easiest implementation might be to just take a copy of
the topic string and use it in mqtt_incoming_data_cb
*/
static int inpub_id;
static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len)
{
printf("Incoming publish at topic %s with total length %u\n", topic, (unsigned int)tot_len);
/* Decode topic string into a user defined reference */
if(strcmp(topic, "print_payload") == 0) {
inpub_id = 0;
} else if(topic[0] == 'A') {
/* All topics starting with 'A' might be handled at the same way */
inpub_id = 1;
} else {
/* For all other topics */
inpub_id = 2;
}
}
static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags)
{
printf("Incoming publish payload with length %d, flags %u\n", len, (unsigned int)flags);
if(flags & MQTT_DATA_FLAG_LAST) {
/* Last fragment of payload received (or whole part if payload fits receive buffer
See MQTT_VAR_HEADER_BUFFER_LEN) */
/* Call function or do action depending on reference, in this case inpub_id */
if(inpub_id == 0) {
/* Don't trust the publisher, check zero termination */
if(data[len-1] == 0) {
printf("mqtt_incoming_data_cb: %s\n", (const char *)data);
}
} else if(inpub_id == 1) {
/* Call an 'A' function... */
} else {
printf("mqtt_incoming_data_cb: Ignoring payload...\n");
}
} else {
/* Handle fragmented payload, store in buffer, write to file or whatever */
}
}
-----------------------------------------------------------------
4. Using outgoing publish
void example_publish(mqtt_client_t *client, void *arg)
{
const char *pub_payload= "PubSubHubLubJub";
err_t err;
u8_t qos = 2; /* 0 1 or 2, see MQTT specification */
u8_t retain = 0; /* No don't retain such crappy payload... */
err = mqtt_publish(client, "pub_topic", pub_payload, strlen(pub_payload), qos, retain, mqtt_pub_request_cb, arg);
if(err != ERR_OK) {
printf("Publish err: %d\n", err);
}
}
/* Called when publish is complete either with sucess or failure */
static void mqtt_pub_request_cb(void *arg, err_t result)
{
if(result != ERR_OK) {
printf("Publish result: %d\n", result);
}
}
-----------------------------------------------------------------
5. Disconnecting
Simply call mqtt_disconnect(client)

View File

@@ -1,529 +0,0 @@
PPP interface for lwIP
Author: Sylvain Rochet
Table of Contents:
1 - Supported PPP protocols and features
2 - Raw API PPP example for all protocols
3 - PPPoS input path (raw API, IRQ safe API, TCPIP API)
4 - Thread safe PPP API (PPPAPI)
5 - Notify phase callback (PPP_NOTIFY_PHASE)
6 - Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x
1 Supported PPP protocols and features
======================================
Supported Low level protocols:
* PPP over serial using HDLC-like framing, such as wired dialup modems
or mobile telecommunications GPRS/EDGE/UMTS/HSPA+/LTE modems
* PPP over Ethernet, such as xDSL modems
* PPP over L2TP (Layer 2 Tunneling Protocol) LAC (L2TP Access Concentrator),
IP tunnel over UDP, such as VPN access
Supported auth protocols:
* PAP, Password Authentication Protocol
* CHAP, Challenge-Handshake Authentication Protocol, also known as CHAP-MD5
* MSCHAPv1, Microsoft version of CHAP, version 1
* MSCHAPv2, Microsoft version of CHAP, version 2
* EAP, Extensible Authentication Protocol
Supported address protocols:
* IPCP, IP Control Protocol, IPv4 addresses negotiation
* IP6CP, IPv6 Control Protocol, IPv6 link-local addresses negotiation
Supported encryption protocols:
* MPPE, Microsoft Point-to-Point Encryption
Supported compression or miscellaneous protocols, for serial links only:
* PFC, Protocol Field Compression
* ACFC, Address-and-Control-Field-Compression
* ACCM, Asynchronous-Control-Character-Map
* VJ, Van Jacobson TCP/IP Header Compression
2 Raw API PPP example for all protocols
=======================================
As usual, raw API for lwIP means the lightweight API which *MUST* only be used
for NO_SYS=1 systems or called inside lwIP core thread for NO_SYS=0 systems.
/*
* Globals
* =======
*/
/* The PPP control block */
ppp_pcb *ppp;
/* The PPP IP interface */
struct netif ppp_netif;
/*
* PPP status callback
* ===================
*
* PPP status callback is called on PPP status change (up, down, …) from lwIP
* core thread
*/
/* PPP status callback example */
static void status_cb(ppp_pcb *pcb, int err_code, void *ctx) {
struct netif *pppif = ppp_netif(pcb);
LWIP_UNUSED_ARG(ctx);
switch(err_code) {
case PPPERR_NONE: {
#if LWIP_DNS
const ip_addr_t *ns;
#endif /* LWIP_DNS */
printf("status_cb: Connected\n");
#if PPP_IPV4_SUPPORT
printf(" our_ipaddr = %s\n", ipaddr_ntoa(&pppif->ip_addr));
printf(" his_ipaddr = %s\n", ipaddr_ntoa(&pppif->gw));
printf(" netmask = %s\n", ipaddr_ntoa(&pppif->netmask));
#if LWIP_DNS
ns = dns_getserver(0);
printf(" dns1 = %s\n", ipaddr_ntoa(ns));
ns = dns_getserver(1);
printf(" dns2 = %s\n", ipaddr_ntoa(ns));
#endif /* LWIP_DNS */
#endif /* PPP_IPV4_SUPPORT */
#if PPP_IPV6_SUPPORT
printf(" our6_ipaddr = %s\n", ip6addr_ntoa(netif_ip6_addr(pppif, 0)));
#endif /* PPP_IPV6_SUPPORT */
break;
}
case PPPERR_PARAM: {
printf("status_cb: Invalid parameter\n");
break;
}
case PPPERR_OPEN: {
printf("status_cb: Unable to open PPP session\n");
break;
}
case PPPERR_DEVICE: {
printf("status_cb: Invalid I/O device for PPP\n");
break;
}
case PPPERR_ALLOC: {
printf("status_cb: Unable to allocate resources\n");
break;
}
case PPPERR_USER: {
printf("status_cb: User interrupt\n");
break;
}
case PPPERR_CONNECT: {
printf("status_cb: Connection lost\n");
break;
}
case PPPERR_AUTHFAIL: {
printf("status_cb: Failed authentication challenge\n");
break;
}
case PPPERR_PROTOCOL: {
printf("status_cb: Failed to meet protocol\n");
break;
}
case PPPERR_PEERDEAD: {
printf("status_cb: Connection timeout\n");
break;
}
case PPPERR_IDLETIMEOUT: {
printf("status_cb: Idle Timeout\n");
break;
}
case PPPERR_CONNECTTIME: {
printf("status_cb: Max connect time reached\n");
break;
}
case PPPERR_LOOPBACK: {
printf("status_cb: Loopback detected\n");
break;
}
default: {
printf("status_cb: Unknown error code %d\n", err_code);
break;
}
}
/*
* This should be in the switch case, this is put outside of the switch
* case for example readability.
*/
if (err_code == PPPERR_NONE) {
return;
}
/* ppp_close() was previously called, don't reconnect */
if (err_code == PPPERR_USER) {
/* ppp_free(); -- can be called here */
return;
}
/*
* Try to reconnect in 30 seconds, if you need a modem chatscript you have
* to do a much better signaling here ;-)
*/
ppp_connect(pcb, 30);
/* OR ppp_listen(pcb); */
}
/*
* Creating a new PPPoS session
* ============================
*
* In lwIP, PPPoS is not PPPoSONET, in lwIP PPPoS is PPPoSerial.
*/
#include "netif/ppp/pppos.h"
/*
* PPPoS serial output callback
*
* ppp_pcb, PPP control block
* data, buffer to write to serial port
* len, length of the data buffer
* ctx, optional user-provided callback context pointer
*
* Return value: len if write succeed
*/
static u32_t output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) {
return uart_write(UART, data, len);
}
/*
* Create a new PPPoS interface
*
* ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
* output_cb, PPPoS serial output callback
* status_cb, PPP status callback, called on PPP status change (up, down, …)
* ctx_cb, optional user-provided callback context pointer
*/
ppp = pppos_create(&ppp_netif,
output_cb, status_cb, ctx_cb);
/*
* Creating a new PPPoE session
* ============================
*/
#include "netif/ppp/pppoe.h"
/*
* Create a new PPPoE interface
*
* ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
* ethif, already existing and setup Ethernet interface to use
* service_name, PPPoE service name discriminator (not supported yet)
* concentrator_name, PPPoE concentrator name discriminator (not supported yet)
* status_cb, PPP status callback, called on PPP status change (up, down, …)
* ctx_cb, optional user-provided callback context pointer
*/
ppp = pppoe_create(&ppp_netif,
&ethif,
service_name, concentrator_name,
status_cb, ctx_cb);
/*
* Creating a new PPPoL2TP session
* ===============================
*/
#include "netif/ppp/pppol2tp.h"
/*
* Create a new PPPoL2TP interface
*
* ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
* netif, optional already existing and setup output netif, necessary if you
* want to set this interface as default route to settle the chicken
* and egg problem with VPN links
* ipaddr, IP to connect to
* port, UDP port to connect to (usually 1701)
* secret, L2TP secret to use
* secret_len, size in bytes of the L2TP secret
* status_cb, PPP status callback, called on PPP status change (up, down, …)
* ctx_cb, optional user-provided callback context pointer
*/
ppp = pppol2tp_create(&ppp_netif,
struct netif *netif, ip_addr_t *ipaddr, u16_t port,
u8_t *secret, u8_t secret_len,
ppp_link_status_cb_fn link_status_cb, void *ctx_cb);
/*
* Initiate PPP client connection
* ==============================
*/
/* Set this interface as default route */
ppp_set_default(ppp);
/*
* Basic PPP client configuration. Can only be set if PPP session is in the
* dead state (i.e. disconnected). We don't need to provide thread-safe
* equivalents through PPPAPI because those helpers are only changing
* structure members while session is inactive for lwIP core. Configuration
* only need to be done once.
*/
/* Ask the peer for up to 2 DNS server addresses. */
ppp_set_usepeerdns(ppp, 1);
/* Auth configuration, this is pretty self-explanatory */
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password");
/*
* Initiate PPP negotiation, without waiting (holdoff=0), can only be called
* if PPP session is in the dead state (i.e. disconnected).
*/
u16_t holdoff = 0;
ppp_connect(ppp, holdoff);
/*
* Initiate PPP server listener
* ============================
*/
/*
* Basic PPP server configuration. Can only be set if PPP session is in the
* dead state (i.e. disconnected). We don't need to provide thread-safe
* equivalents through PPPAPI because those helpers are only changing
* structure members while session is inactive for lwIP core. Configuration
* only need to be done once.
*/
ip4_addr_t addr;
/* Set our address */
IP4_ADDR(&addr, 192,168,0,1);
ppp_set_ipcp_ouraddr(ppp, &addr);
/* Set peer(his) address */
IP4_ADDR(&addr, 192,168,0,2);
ppp_set_ipcp_hisaddr(ppp, &addr);
/* Set primary DNS server */
IP4_ADDR(&addr, 192,168,10,20);
ppp_set_ipcp_dnsaddr(ppp, 0, &addr);
/* Set secondary DNS server */
IP4_ADDR(&addr, 192,168,10,21);
ppp_set_ipcp_dnsaddr(ppp, 1, &addr);
/* Auth configuration, this is pretty self-explanatory */
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password");
/* Require peer to authenticate */
ppp_set_auth_required(ppp, 1);
/*
* Only for PPPoS, the PPP session should be up and waiting for input.
*
* Note: for PPPoS, ppp_connect() and ppp_listen() are actually the same thing.
* The listen call is meant for future support of PPPoE and PPPoL2TP server
* mode, where we will need to negotiate the incoming PPPoE session or L2TP
* session before initiating PPP itself. We need this call because there is
* two passive modes for PPPoS, ppp_set_passive and ppp_set_silent.
*/
ppp_set_silent(pppos, 1);
/*
* Initiate PPP listener (i.e. wait for an incoming connection), can only
* be called if PPP session is in the dead state (i.e. disconnected).
*/
ppp_listen(ppp);
/*
* Closing PPP connection
* ======================
*/
/*
* Initiate the end of the PPP session, without carrier lost signal
* (nocarrier=0), meaning a clean shutdown of PPP protocols.
* You can call this function at anytime.
*/
u8_t nocarrier = 0;
ppp_close(ppp, nocarrier);
/*
* Then you must wait your status_cb() to be called, it may takes from a few
* seconds to several tens of seconds depending on the current PPP state.
*/
/*
* Freeing a PPP connection
* ========================
*/
/*
* Free the PPP control block, can only be called if PPP session is in the
* dead state (i.e. disconnected). You need to call ppp_close() before.
*/
ppp_free(ppp);
3 PPPoS input path (raw API, IRQ safe API, TCPIP API)
=====================================================
Received data on serial port should be sent to lwIP using the pppos_input()
function or the pppos_input_tcpip() function.
If NO_SYS is 1 and if PPP_INPROC_IRQ_SAFE is 0 (the default), pppos_input()
is not IRQ safe and then *MUST* only be called inside your main loop.
Whatever the NO_SYS value, if PPP_INPROC_IRQ_SAFE is 1, pppos_input() is IRQ
safe and can be safely called from an interrupt context, using that is going
to reduce your need of buffer if pppos_input() is called byte after byte in
your rx serial interrupt.
if NO_SYS is 0, the thread safe way outside an interrupt context is to use
the pppos_input_tcpip() function to pass input data to the lwIP core thread
using the TCPIP API. This is thread safe in all cases but you should avoid
passing data byte after byte because it uses heavy locking (mailbox) and it
allocates pbuf, better fill them !
if NO_SYS is 0 and if PPP_INPROC_IRQ_SAFE is 1, you may also use pppos_input()
from an RX thread, however pppos_input() is not thread safe by itself. You can
do that *BUT* you should NEVER call pppos_connect(), pppos_listen() and
ppp_free() if pppos_input() can still be running, doing this is NOT thread safe
at all. Using PPP_INPROC_IRQ_SAFE from an RX thread is discouraged unless you
really know what you are doing, your move ;-)
/*
* Fonction to call for received data
*
* ppp, PPP control block
* buffer, input buffer
* buffer_len, buffer length in bytes
*/
void pppos_input(ppp, buffer, buffer_len);
or
void pppos_input_tcpip(ppp, buffer, buffer_len);
4 Thread safe PPP API (PPPAPI)
==============================
There is a thread safe API for all corresponding ppp_* functions, you have to
enable LWIP_PPP_API in your lwipopts.h file, then see
include/netif/ppp/pppapi.h, this is actually pretty obvious.
5 Notify phase callback (PPP_NOTIFY_PHASE)
==========================================
Notify phase callback, enabled using the PPP_NOTIFY_PHASE config option, let
you configure a callback that is called on each PPP internal state change.
This is different from the status callback which only warns you about
up(running) and down(dead) events.
Notify phase callback can be used, for example, to set a LED pattern depending
on the current phase of the PPP session. Here is a callback example which
tries to mimic what we usually see on xDSL modems while they are negotiating
the link, which should be self-explanatory:
static void ppp_notify_phase_cb(ppp_pcb *pcb, u8_t phase, void *ctx) {
switch (phase) {
/* Session is down (either permanently or briefly) */
case PPP_PHASE_DEAD:
led_set(PPP_LED, LED_OFF);
break;
/* We are between two sessions */
case PPP_PHASE_HOLDOFF:
led_set(PPP_LED, LED_SLOW_BLINK);
break;
/* Session just started */
case PPP_PHASE_INITIALIZE:
led_set(PPP_LED, LED_FAST_BLINK);
break;
/* Session is running */
case PPP_PHASE_RUNNING:
led_set(PPP_LED, LED_ON);
break;
default:
break;
}
}
6 Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x
===============================================
PPP API was fully reworked between 1.4.x and 2.0.x releases. However porting
from previous lwIP version is pretty easy:
* Previous PPP API used an integer to identify PPP sessions, we are now
using ppp_pcb* control block, therefore all functions changed from "int ppp"
to "ppp_pcb *ppp"
* struct netif was moved outside the PPP structure, you have to provide a netif
for PPP interface in pppoX_create() functions
* PPP session are not started automatically after you created them anymore,
you have to call ppp_connect(), this way you can configure the session before
starting it.
* Previous PPP API used CamelCase, we are now using snake_case.
* Previous PPP API mixed PPPoS and PPPoE calls, this isn't the case anymore,
PPPoS functions are now prefixed pppos_ and PPPoE functions are now prefixed
pppoe_, common functions are now prefixed ppp_.
* New PPPERR_ error codes added, check you have all of them in your status
callback function
* Only the following include files should now be used in user application:
#include "netif/ppp/pppapi.h"
#include "netif/ppp/pppos.h"
#include "netif/ppp/pppoe.h"
#include "netif/ppp/pppol2tp.h"
Functions from ppp.h can be used, but you don't need to include this header
file as it is already included by above header files.
* PPP_INPROC_OWNTHREAD was broken by design and was removed, you have to create
your own serial rx thread
* PPP_INPROC_MULTITHREADED option was misnamed and confusing and was renamed
PPP_INPROC_IRQ_SAFE, please read the "PPPoS input path" documentation above
because you might have been fooled by that
* If you used tcpip_callback_with_block() on ppp_ functions you may wish to use
the PPPAPI API instead.
* ppp_sighup and ppp_close functions were merged using an optional argument
"nocarrier" on ppp_close.
* DNS servers are now only remotely asked if LWIP_DNS is set and if
ppp_set_usepeerdns() is set to true, they are now automatically registered
using the dns_setserver() function so you don't need to do that in the PPP
callback anymore.
* PPPoS does not use the SIO API anymore, as such it now requires a serial
output callback in place of sio_write
* PPP_MAXIDLEFLAG is now in ms instead of jiffies

View File

@@ -8,12 +8,6 @@ to use for communication with the TCP/IP code:
* higher-level "sequential" API.
* BSD-style socket API.
The raw API (sometimes called native API) is an event-driven API designed
to be used without an operating system that implements zero-copy send and
receive. This API is also used by the core stack for interaction between
the various protocols. It is the only API available when running lwIP
without an operating system.
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
model of execution is based on the blocking open-read-write-close
@@ -28,17 +22,14 @@ 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.
** Multithreading
** 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"). When running in a multithreaded
environment, raw API functions MUST only be called from the core thread
since raw API functions are not protected from concurrent access (aside
from pbuf- and memory management functions). Application threads using
the sequential- or socket API communicate with this main thread through
message passing.
(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
@@ -47,7 +38,6 @@ message passing.
- netbuf.h
- netdb.h
- netifapi.h
- pppapi.h
- sockets.h
- sys.h
@@ -56,18 +46,13 @@ message passing.
since they are protected by SYS_LIGHTWEIGHT_PROT and/or
semaphores.
Netconn or Socket API functions are thread safe against the
core thread but they are not reentrant at the control block
granularity level. That is, a UDP or TCP control block must
not be shared among multiple threads without proper locking.
If SYS_LIGHTWEIGHT_PROT is set to 1 and
LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
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. **
@@ -86,28 +71,13 @@ the raw TCP/IP interface are more difficult to understand. Still, this
is the preferred way of writing applications that should be small in
code size and memory usage.
All APIs can be used simultaneously by different application
Both APIs can be used simultaneously by different application
programs. In fact, the sequential API is implemented as an application
program using the raw TCP/IP interface.
Do not confuse the lwIP raw API with raw Ethernet or IP sockets.
The former is a way of interfacing the lwIP network stack (including
TCP and UDP), the later refers to processing raw Ethernet or IP data
instead of TCP connections or UDP packets.
Raw API applications may never block since all packet processing
(input and output) as well as timer processing (TCP mainly) is done
in a single execution context.
--- Callbacks
Program execution is driven by callbacks functions, which are then
invoked by the lwIP core when activity related to that application
occurs. A particular application may register to be notified via a
callback function for events such as incoming data available, outgoing
data sent, error notifications, poll timer expiration, connection
closed, etc. An application can provide a callback function to perform
processing for any or all of these events. Each callback is an ordinary
Program execution is driven by callbacks. Each callback is an ordinary
C function that is called from within the TCP/IP code. Every callback
function is passed the current TCP or UDP connection state as an
argument. Also, in order to be able to keep program specific state,
@@ -171,6 +141,15 @@ incoming connections or be explicitly connected to another host.
in the listen queue to the value specified by the backlog argument.
To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.
- void tcp_accepted(struct tcp_pcb *pcb)
Inform lwIP that an incoming connection has been accepted. This would
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,
err_t err))
@@ -217,7 +196,7 @@ callback function.
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 omitted,
- 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.
@@ -323,6 +302,17 @@ function to be called is set using the tcp_err() function.
parameter since the pcb may already have been deallocated.
--- Lower layer TCP interface
TCP provides a simple interface to the lower layers of the
system. During system initialization, the function tcp_init() has
to be called before any other TCP function is called. When the system
is running, the two timer functions tcp_fasttmr() and tcp_slowtmr()
must be called with regular intervals. The tcp_fasttmr() should be
called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and
tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds.
--- UDP interface
The UDP interface is similar to that of TCP, but due to the lower
@@ -373,9 +363,9 @@ level of complexity of UDP, the interface is significantly simpler.
--- System initalization
A truly complete and generic sequence for initializing the lwIP stack
cannot be given because it depends on additional initializations for
your runtime environment (e.g. timers).
A truly complete and generic sequence for initializing the lwip stack
cannot be given because it depends on the build configuration (lwipopts.h)
and additional initializations for your runtime environment (e.g. timers).
We can give you some idea on how to proceed when using the raw API.
We assume a configuration using a single Ethernet netif and the
@@ -383,13 +373,51 @@ UDP and TCP transport layers, IPv4 and the DHCP client.
Call these functions in the order of appearance:
- lwip_init()
- stats_init()
Initialize the lwIP stack and all of its subsystems.
Clears the structure where runtime statistics are gathered.
- netif_add(struct netif *netif, const ip4_addr_t *ipaddr,
const ip4_addr_t *netmask, const ip4_addr_t *gw,
void *state, netif_init_fn init, netif_input_fn input)
- sys_init()
Not of much use since we set the NO_SYS 1 option in lwipopts.h,
to be called for easy configuration changes.
- mem_init()
Initializes the dynamic memory heap defined by MEM_SIZE.
- memp_init()
Initializes the memory pools defined by MEMP_NUM_x.
- pbuf_init()
Initializes the pbuf memory pool defined by PBUF_POOL_SIZE.
- etharp_init()
Initializes the ARP table and queue.
Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval
after this initialization.
- ip_init()
Doesn't do much, it should be called to handle future changes.
- udp_init()
Clears the UDP PCB list.
- tcp_init()
Clears the TCP PCB list and clears some internal TCP timers.
Note: you must call tcp_fasttmr() and tcp_slowtmr() at the
predefined regular intervals after this initialization.
- 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))
Adds your network interface to the netif_list. Allocate a struct
netif and pass a pointer to this structure as the first argument.
@@ -397,20 +425,18 @@ Call these functions in the order of appearance:
or fill them with sane numbers otherwise. The state pointer may be NULL.
The init function pointer must point to a initialization function for
your Ethernet netif interface. The following code illustrates its use.
your ethernet netif interface. The following code illustrates it's use.
err_t netif_if_init(struct netif *netif)
{
u8_t i;
for (i = 0; i < ETHARP_HWADDR_LEN; i++) {
netif->hwaddr[i] = some_eth_addr[i];
}
for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i];
init_my_eth_device();
return ERR_OK;
}
For Ethernet drivers, the input function pointer must point to the lwIP
For ethernet drivers, the input function pointer must point to the lwip
function ethernet_input() declared in "netif/etharp.h". Other drivers
must use ip_input() declared in "lwip/ip.h".
@@ -418,30 +444,18 @@ Call these functions in the order of appearance:
Registers the default network interface.
- netif_set_link_up(struct netif *netif)
This is the hardware link state; e.g. whether cable is plugged for wired
Ethernet interface. This function must be called even if you don't know
the current state. Having link up and link down events is optional but
DHCP and IPv6 discover benefit well from those events.
- netif_set_up(struct netif *netif)
This is the administrative (= software) state of the netif, when the
netif is fully configured this function must be called.
When the netif is fully configured this function must be called.
- dhcp_start(struct netif *netif)
Creates a new DHCP client for this interface on the first call.
Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
the predefined regular intervals after starting the client.
You can peek in the netif->dhcp struct for the actual DHCP status.
- sys_check_timeouts()
When the system is running, you have to periodically call
sys_check_timeouts() which will handle all timers for all protocols in
the stack; add this to your main loop or equivalent.
--- Optimalization hints
@@ -456,11 +470,9 @@ introduction to this subject.
Other significant improvements can be made by supplying
assembly or inline replacements for htons() and htonl()
if you're using a little-endian architecture.
#define lwip_htons(x) <your_htons>
#define lwip_htonl(x) <your_htonl>
If you #define them to htons() and htonl(), you should
#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from
defining hton*/ntoh* compatibility macros.
#define LWIP_PLATFORM_BYTESWAP 1
#define LWIP_PLATFORM_HTONS(x) <your_htons>
#define LWIP_PLATFORM_HTONL(x) <your_htonl>
Check your network interface driver if it reads at
a higher speed than the maximum wire-speed. If the

View File

@@ -2,34 +2,37 @@ Daily Use Guide for using Savannah for lwIP
Table of Contents:
1 - Obtaining lwIP from the Git repository
2 - Committers/developers Git access using SSH
3 - Merging a development branch to master branch
1 - Obtaining lwIP from the CVS repository
2 - Committers/developers CVS access using SSH (to be written)
3 - Merging from DEVEL branch to main trunk (stable branch)
4 - How to release lwIP
1 Obtaining lwIP from the Git repository
1 Obtaining lwIP from the CVS repository
----------------------------------------
To perform an anonymous Git clone of the master branch (this is where
To perform an anonymous CVS checkout of the main trunk (this is where
bug fixes and incremental enhancements occur), do this:
git clone git://git.savannah.nongnu.org/lwip.git
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout lwip
Or, obtain a stable branch (updated with bug fixes only) as follows:
git clone --branch DEVEL-1_4_1 git://git.savannah.nongnu.org/lwip.git
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
-r STABLE-0_7 -d lwip-0.7 lwip
Or, obtain a specific (fixed) release as follows:
git clone --branch STABLE-1_4_1 git://git.savannah.nongnu.org/lwip.git
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
-r STABLE-0_7_0 -d lwip-0.7.0 lwip
2 Committers/developers Git access using SSH
3 Committers/developers CVS access using SSH
--------------------------------------------
The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
As such, Git commits to the server occur through a SSH tunnel for project members.
As such, CVS commits to the server occur through a SSH tunnel for project members.
To create a SSH2 key pair in UNIX-like environments, do this:
ssh-keygen -t dsa
ssh-keygen -t dsa
Under Windows, a recommended SSH client is "PuTTY", freely available with good
documentation and a graphic user interface. Use its key generator.
@@ -38,83 +41,95 @@ Now paste the id_dsa.pub contents into your Savannah account public key list. Wa
a while so that Savannah can update its configuration (This can take minutes).
Try to login using SSH:
ssh -v your_login@git.sv.gnu.org
ssh -v your_login@cvs.sv.gnu.org
If it tells you:
Linux vcs.savannah.gnu.org 2.6.32-5-xen-686 #1 SMP Wed Jun 17 17:10:03 UTC 2015 i686
Interactive shell login is not possible for security reasons.
VCS commands are allowed.
Last login: Tue May 15 23:10:12 2012 from 82.245.102.129
You tried to execute:
Sorry, you are not allowed to execute that command.
Shared connection to git.sv.gnu.org closed.
Authenticating with public key "your_key_name"...
Server refused to allocate pty
then you could login; Savannah refuses to give you a shell - which is OK, as we
are allowed to use SSH for Git only. Now, you should be able to do this:
git clone your_login@git.sv.gnu.org:/srv/git/lwip.git
are allowed to use SSH for CVS only. Now, you should be able to do this:
After which you can edit your local files with bug fixes or new features and
commit them. Make sure you know what you are doing when using Git to make
export CVS_RSH=ssh
cvs -z3 -d:ext:your_login@cvs.sv.gnu.org:/sources/lwip co lwip
after which you can edit your local files with bug fixes or new features and
commit them. Make sure you know what you are doing when using CVS to make
changes on the repository. If in doubt, ask on the lwip-members mailing list.
(If SSH asks about authenticity of the host, you can check the key
fingerprint against https://savannah.nongnu.org/git/?group=lwip
fingerprint against http://savannah.nongnu.org/cvs/?group=lwip)
3 - Merging a development branch to master branch
-------------------------------------------------
3 Merging from DEVEL branch to main trunk (stable)
--------------------------------------------------
Merging is a straightforward process in Git. How to merge all changes in a
development branch since our last merge from main:
Merging is a delicate process in CVS and requires the
following disciplined steps in order to prevent conflicts
in the future. Conflicts can be hard to solve!
Checkout the master branch:
git checkout master
Merging from branch A to branch B requires that the A branch
has a tag indicating the previous merger. This tag is called
'merged_from_A_to_B'. After merging, the tag is moved in the
A branch to remember this merger for future merge actions.
Merge the development branch to master:
git merge your-development-branch
IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE
REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE
MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME).
Resolve any conflict.
Merge all changes in DEVEL since our last merge to main:
Commit the merge result.
git commit -a
In the working copy of the main trunk:
cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL
Push your commits:
git push
(This will apply the changes between 'merged_from_DEVEL_to_main'
and 'DEVEL' to your work set of files)
We can now commit the merge result.
cvs commit -R -m "Merged from DEVEL to main."
If this worked out OK, we now move the tag in the DEVEL branch
to this merge point, so we can use this point for future merges:
cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip
4 How to release lwIP
---------------------
First, tag the release using Git: (I use release number 1.4.1 throughout
this example).
git tag -a STABLE-1_4_1
First, checkout a clean copy of the branch to be released. Tag this set with
tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example).
Share the tag reference by pushing it to remote:
git push origin STABLE-1_4_1
Login CVS using pserver authentication, then export a clean copy of the
tagged tree. Export is similar to a checkout, except that the CVS metadata
is not created locally.
Prepare the release:
cp -r lwip lwip-1.4.1
rm -rf lwip-1.4.1/.git lwip-1.4.1/.gitattributes
export CVS_RSH=ssh
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
-r STABLE-0_6_3 -d lwip-0.6.3 lwip
Archive the current directory using tar, gzip'd, bzip2'd and zip'd.
tar czvf lwip-1.4.1.tar.gz lwip-1.4.1
tar cjvf lwip-1.4.1.tar.bz2 lwip-1.4.1
zip -r lwip-1.4.1.zip lwip-1.4.1
Archive this directory using tar, gzip'd, bzip2'd and zip'd.
tar czvf lwip-0.6.3.tar.gz lwip-0.6.3
tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3
zip -r lwip-0.6.3.zip lwip-0.6.3
Now, sign the archives with a detached GPG binary signature as follows:
gpg -b lwip-1.4.1.tar.gz
gpg -b lwip-1.4.1.tar.bz2
gpg -b lwip-1.4.1.zip
gpg -b lwip-0.6.3.tar.gz
gpg -b lwip-0.6.3.tar.bz2
gpg -b lwip-0.6.3.zip
Upload these files using anonymous FTP:
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
ncftp> mput *1.4.1.*
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
ncftp>mput *0.6.3.*
Additionally, you may post a news item on Savannah, like this:
A new 1.4.1 release is now available here:
http://savannah.nongnu.org/files/?group=lwip&highlight=1.4.1
A new 0.6.3 release is now available here:
http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3
You will have to submit this via the user News interface, then approve
this via the Administrator News interface.
this via the Administrator News interface.

181
doc/snmp_agent.txt Normal file
View File

@@ -0,0 +1,181 @@
SNMPv1 agent for lwIP
Author: Christiaan Simons
This is a brief introduction how to use and configure the SNMP agent.
Note the agent uses the raw-API UDP interface so you may also want to
read rawapi.txt to gain a better understanding of the SNMP message handling.
0 Agent Capabilities
====================
SNMPv1 per RFC1157
This is an old(er) standard but is still widely supported.
For SNMPv2c and v3 have a greater complexity and need many
more lines of code. IMHO this breaks the idea of "lightweight IP".
Note the S in SNMP stands for "Simple". Note that "Simple" is
relative. SNMP is simple compared to the complex ISO network
management protocols CMIP (Common Management Information Protocol)
and CMOT (CMip Over Tcp).
MIB II per RFC1213
The standard lwIP stack management information base.
This is a required MIB, so this is always enabled.
When builing lwIP without TCP, the mib-2.tcp group is omitted.
The groups EGP, CMOT and transmission are disabled by default.
Most mib-2 objects are not writable except:
sysName, sysLocation, sysContact, snmpEnableAuthenTraps.
Writing to or changing the ARP and IP address and route
tables is not possible.
Note lwIP has a very limited notion of IP routing. It currently
doen't have a route table and doesn't have a notion of the U,G,H flags.
Instead lwIP uses the interface list with only one default interface
acting as a single gateway interface (G) for the default route.
The agent returns a "virtual table" with the default route 0.0.0.0
for the default interface and network routes (no H) for each
network interface in the netif_list.
All routes are considered to be up (U).
Loading additional MIBs
MIBs can only be added in compile-time, not in run-time.
There is no MIB compiler thus additional MIBs must be hand coded.
Large SNMP message support
The packet decoding and encoding routines are designed
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.
1 Building the Agent
====================
First of all you'll need to add the following define
to your local lwipopts.h:
#define LWIP_SNMP 1
and add the source files in lwip/src/core/snmp
and some snmp headers in lwip/src/include/lwip to your makefile.
Note you'll might need to adapt you network driver to update
the mib2 variables for your interface.
2 Running the Agent
===================
The following function calls must be made in your program to
actually get the SNMP agent running.
Before starting the agent you should supply pointers
to non-volatile memory for sysContact, sysLocation,
and snmpEnableAuthenTraps. You can do this by calling
snmp_set_syscontact()
snmp_set_syslocation()
snmp_set_snmpenableauthentraps()
Additionally you may want to set
snmp_set_sysdescr()
snmp_set_sysobjid() (if you have a private MIB)
snmp_set_sysname()
Also before starting the agent you need to setup
one or more trap destinations using these calls:
snmp_trap_dst_enable();
snmp_trap_dst_ip_set();
In the lwIP initialisation sequence call snmp_init() just after
the call to udp_init().
Exactly every 10 msec the SNMP uptime timestamp must be updated with
snmp_inc_sysuptime(). You should call this from a timer interrupt
or a timer signal handler depending on your runtime environment.
An alternative way to update the SNMP uptime timestamp is to do a call like
snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to
a lower frequency). Another one is to not call snmp_inc_sysuptime() or
snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro.
This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside
snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only
when it's queried (any function which need "sysuptime" have to call
snmp_get_sysuptime).
3 Private MIBs
==============
If want to extend the agent with your own private MIB you'll need to
add the following define to your local lwipopts.h:
#define SNMP_PRIVATE_MIB 1
You must provide the private_mib.h and associated files yourself.
Note we don't have a "MIB compiler" that generates C source from a MIB,
so you're required to do some serious coding if you enable this!
Note the lwIP enterprise ID (26381) is assigned to the lwIP project,
ALL OBJECT IDENTIFIERS LIVING UNDER THIS ID ARE ASSIGNED BY THE lwIP
MAINTAINERS!
If you need to create your own private MIB you'll need
to apply for your own enterprise ID with IANA: http://www.iana.org/numbers.html
You can set it by passing a struct snmp_obj_id to the agent
using snmp_set_sysobjid(&my_object_id), just before snmp_init().
Note the object identifiers for thes MIB-2 and your private MIB
tree must be kept in sorted ascending (lexicographical) order.
This to ensure correct getnext operation.
An example for a private MIB is part of the "minimal Unix" project:
contrib/ports/unix/proj/minimal/lwip_prvmib.c
The next chapter gives a more detailed description of the
MIB-2 tree and the optional private MIB.
4 The Gory Details
==================
4.0 Object identifiers and the MIB tree.
We have three distinct parts for all object identifiers:
The prefix
.iso.org.dod.internet
the middle part
.mgmt.mib-2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress
and the index part
.1.192.168.0.1
Objects located above the .internet hierarchy aren't supported.
Currently only the .mgmt sub-tree is available and
when the SNMP_PRIVATE_MIB is enabled the .private tree
becomes available too.
Object identifiers from incoming requests are checked
for a matching prefix, middle part and index part
or are expanded(*) for GetNext requests with short
or inexisting names in the request.
(* we call this "expansion" but this also
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 a dynamically
changing private tree.
The index part is handled by functions which in
turn use dynamically allocated index trees from RAM.
These trees are updated by e.g. the etharp code
when new entries are made or removed form the ARP cache.
/** @todo more gory details */

View File

@@ -1,7 +1,6 @@
sys_arch interface for lwIP
sys_arch interface for lwIP 0.6++
Author: Adam Dunkels
Simon Goldschmidt
The operating system emulation layer provides a common interface
between the lwIP code and the underlying operating system kernel. The
@@ -10,11 +9,12 @@ small changes to a few header files and a new sys_arch
implementation. It is also possible to do a sys_arch implementation
that does not rely on any underlying operating system.
The sys_arch provides semaphores, mailboxes and mutexes to lwIP. For the full
The sys_arch provides semaphores and mailboxes to lwIP. For the full
lwIP functionality, multiple threads support can be implemented in the
sys_arch, but this is not required for the basic lwIP
functionality. Timer scheduling is implemented in lwIP, but can be implemented
by the sys_arch port (LWIP_TIMERS_CUSTOM==1).
functionality. Previous versions of lwIP required the sys_arch to
implement timer scheduling as well but as of lwIP 0.5 this is
implemented in a higher layer.
In addition to the source file providing the functionality of sys_arch,
the OS emulation layer must provide several header files defining
@@ -22,18 +22,19 @@ macros used throughout lwip. The files required and the macros they
must define are listed below the sys_arch description.
Semaphores can be either counting or binary - lwIP works with both
kinds. Mailboxes should be implemented as a queue which allows multiple messages
to be posted (implementing as a rendez-vous point where only one message can be
posted at a time can have a highly negative impact on performance). A message
in a mailbox is just a pointer, nothing more.
kinds. Mailboxes are used for message passing and can be implemented
either as a queue which allows multiple messages to be posted to a
mailbox, or as a rendez-vous point where only one message can be
posted at a time. lwIP works with both kinds, but the former type will
be more efficient. A message in a mailbox is just a pointer, nothing
more.
Semaphores are represented by the type "sys_sem_t" which is typedef'd
in the sys_arch.h file. Mailboxes are equivalently represented by the
type "sys_mbox_t". Mutexes are represented by the type "sys_mutex_t".
lwIP does not place any restrictions on how these types are represented
internally.
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, mutexes and mailbox functions are prototyped in a way that
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).
@@ -93,40 +94,6 @@ The following functions must be implemented by the sys_arch:
sys_sem_free() is always called before calling this function!
This may also be a define, in which case the function is not prototyped.
- void sys_mutex_new(sys_mutex_t *mutex)
Creates a new mutex. The mutex is allocated to the memory that 'mutex'
points to (which can be both a pointer or the actual OS structure).
If the mutex 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_mutex_free(sys_mutex_t *mutex)
Deallocates a mutex.
- void sys_mutex_lock(sys_mutex_t *mutex)
Blocks the thread until the mutex can be grabbed.
- void sys_mutex_unlock(sys_mutex_t *mutex)
Releases the mutex previously locked through 'sys_mutex_lock()'.
- void sys_mutex_valid(sys_mutex_t *mutex)
Returns 1 if the mutes 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_mutex_set_invalid(sys_mutex_t *mutex)
Invalidate a mutex so that sys_mutex_valid() returns 0.
ATTENTION: This does NOT mean that the mutex shall be deallocated:
sys_mutex_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
@@ -209,9 +176,6 @@ to be implemented as well:
the "stacksize" parameter. The id of the new thread is returned. Both the id
and the priority are system dependent.
When lwIP is used from more than one context (e.g. from multiple threads OR from
main-loop and from interrupts), the SYS_LIGHTWEIGHT_PROT protection SHOULD be enabled!
- sys_prot_t sys_arch_protect(void)
This optional function does a "fast" critical region protection and returns
@@ -245,7 +209,7 @@ For some configurations, you also need:
Note:
Be careful with using mem_malloc() in sys_arch. When malloc() refers to
Be carefull with using mem_malloc() in sys_arch. When malloc() refers to
mem_malloc() you can run into a circular function call problem. In mem.c
mem_init() tries to allcate a semaphore using mem_malloc, which of course
can't be performed when sys_arch uses mem_malloc.

View File

@@ -1,15 +1,13 @@
api/ - The code for the high-level wrapper API. Not needed if
you use the lowel-level call-back/raw API.
apps/ - Higher layer applications that are specifically programmed
with the lwIP low-level raw API.
core/ - The core of the TPC/IP stack; protocol implementations,
memory and buffer management, and the low-level raw API.
include/ - lwIP include files.
netif/ - Generic network interface device drivers are kept here.
netif/ - Generic network interface device drivers are kept here,
as well as the ARP module.
For more information on the various subdirectories, check the FILES
file in each directory.

View File

@@ -1,181 +0,0 @@
#
# Copyright (c) 2001, 2002 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>
#
# COREFILES, CORE4FILES: The minimum set of files needed for lwIP.
COREFILES=$(LWIPDIR)/core/init.c \
$(LWIPDIR)/core/def.c \
$(LWIPDIR)/core/dns.c \
$(LWIPDIR)/core/inet_chksum.c \
$(LWIPDIR)/core/ip.c \
$(LWIPDIR)/core/mem.c \
$(LWIPDIR)/core/memp.c \
$(LWIPDIR)/core/netif.c \
$(LWIPDIR)/core/pbuf.c \
$(LWIPDIR)/core/raw.c \
$(LWIPDIR)/core/stats.c \
$(LWIPDIR)/core/sys.c \
$(LWIPDIR)/core/tcp.c \
$(LWIPDIR)/core/tcp_in.c \
$(LWIPDIR)/core/tcp_out.c \
$(LWIPDIR)/core/timeouts.c \
$(LWIPDIR)/core/udp.c
CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c \
$(LWIPDIR)/core/ipv4/dhcp.c \
$(LWIPDIR)/core/ipv4/etharp.c \
$(LWIPDIR)/core/ipv4/icmp.c \
$(LWIPDIR)/core/ipv4/igmp.c \
$(LWIPDIR)/core/ipv4/ip4_frag.c \
$(LWIPDIR)/core/ipv4/ip4.c \
$(LWIPDIR)/core/ipv4/ip4_addr.c
CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c \
$(LWIPDIR)/core/ipv6/ethip6.c \
$(LWIPDIR)/core/ipv6/icmp6.c \
$(LWIPDIR)/core/ipv6/inet6.c \
$(LWIPDIR)/core/ipv6/ip6.c \
$(LWIPDIR)/core/ipv6/ip6_addr.c \
$(LWIPDIR)/core/ipv6/ip6_frag.c \
$(LWIPDIR)/core/ipv6/mld6.c \
$(LWIPDIR)/core/ipv6/nd6.c
# APIFILES: The files which implement the sequential and socket APIs.
APIFILES=$(LWIPDIR)/api/api_lib.c \
$(LWIPDIR)/api/api_msg.c \
$(LWIPDIR)/api/err.c \
$(LWIPDIR)/api/netbuf.c \
$(LWIPDIR)/api/netdb.c \
$(LWIPDIR)/api/netifapi.c \
$(LWIPDIR)/api/sockets.c \
$(LWIPDIR)/api/tcpip.c
# NETIFFILES: Files implementing various generic network interface functions
NETIFFILES=$(LWIPDIR)/netif/ethernet.c \
$(LWIPDIR)/netif/slipif.c
# SIXLOWPAN: 6LoWPAN
SIXLOWPAN=$(LWIPDIR)/netif/lowpan6.c \
# PPPFILES: PPP
PPPFILES=$(LWIPDIR)/netif/ppp/auth.c \
$(LWIPDIR)/netif/ppp/ccp.c \
$(LWIPDIR)/netif/ppp/chap-md5.c \
$(LWIPDIR)/netif/ppp/chap_ms.c \
$(LWIPDIR)/netif/ppp/chap-new.c \
$(LWIPDIR)/netif/ppp/demand.c \
$(LWIPDIR)/netif/ppp/eap.c \
$(LWIPDIR)/netif/ppp/ecp.c \
$(LWIPDIR)/netif/ppp/eui64.c \
$(LWIPDIR)/netif/ppp/fsm.c \
$(LWIPDIR)/netif/ppp/ipcp.c \
$(LWIPDIR)/netif/ppp/ipv6cp.c \
$(LWIPDIR)/netif/ppp/lcp.c \
$(LWIPDIR)/netif/ppp/magic.c \
$(LWIPDIR)/netif/ppp/mppe.c \
$(LWIPDIR)/netif/ppp/multilink.c \
$(LWIPDIR)/netif/ppp/ppp.c \
$(LWIPDIR)/netif/ppp/pppapi.c \
$(LWIPDIR)/netif/ppp/pppcrypt.c \
$(LWIPDIR)/netif/ppp/pppoe.c \
$(LWIPDIR)/netif/ppp/pppol2tp.c \
$(LWIPDIR)/netif/ppp/pppos.c \
$(LWIPDIR)/netif/ppp/upap.c \
$(LWIPDIR)/netif/ppp/utils.c \
$(LWIPDIR)/netif/ppp/vj.c \
$(LWIPDIR)/netif/ppp/polarssl/arc4.c \
$(LWIPDIR)/netif/ppp/polarssl/des.c \
$(LWIPDIR)/netif/ppp/polarssl/md4.c \
$(LWIPDIR)/netif/ppp/polarssl/md5.c \
$(LWIPDIR)/netif/ppp/polarssl/sha1.c
# LWIPNOAPPSFILES: All LWIP files without apps
LWIPNOAPPSFILES=$(COREFILES) \
$(CORE4FILES) \
$(CORE6FILES) \
$(APIFILES) \
$(NETIFFILES) \
$(PPPFILES) \
$(SIXLOWPAN)
# SNMPFILES: SNMPv2c agent
SNMPFILES=$(LWIPDIR)/apps/snmp/snmp_asn1.c \
$(LWIPDIR)/apps/snmp/snmp_core.c \
$(LWIPDIR)/apps/snmp/snmp_mib2.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_icmp.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_interfaces.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_ip.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_snmp.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_system.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_tcp.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_udp.c \
$(LWIPDIR)/apps/snmp/snmp_msg.c \
$(LWIPDIR)/apps/snmp/snmpv3.c \
$(LWIPDIR)/apps/snmp/snmp_netconn.c \
$(LWIPDIR)/apps/snmp/snmp_pbuf_stream.c \
$(LWIPDIR)/apps/snmp/snmp_raw.c \
$(LWIPDIR)/apps/snmp/snmp_scalar.c \
$(LWIPDIR)/apps/snmp/snmp_table.c \
$(LWIPDIR)/apps/snmp/snmp_threadsync.c \
$(LWIPDIR)/apps/snmp/snmp_traps.c \
$(LWIPDIR)/apps/snmp/snmpv3_mbedtls.c \
$(LWIPDIR)/apps/snmp/snmpv3_dummy.c
# HTTPDFILES: HTTP server
HTTPDFILES=$(LWIPDIR)/apps/httpd/fs.c \
$(LWIPDIR)/apps/httpd/httpd.c
# LWIPERFFILES: IPERF server
LWIPERFFILES=$(LWIPDIR)/apps/lwiperf/lwiperf.c
# SNTPFILES: SNTP client
SNTPFILES=$(LWIPDIR)/apps/sntp/sntp.c
# MDNSFILES: MDNS responder
MDNSFILES=$(LWIPDIR)/apps/mdns/mdns.c
# NETBIOSNSFILES: NetBIOS name server
NETBIOSNSFILES=$(LWIPDIR)/apps/netbiosns/netbiosns.c
# TFTPFILES: TFTP server files
TFTPFILES=$(LWIPDIR)/apps/tftp/tftp_server.c
# MQTTFILES: MQTT client files
MQTTFILES=$(LWIPDIR)/apps/mqtt/mqtt.c
# LWIPAPPFILES: All LWIP APPs
LWIPAPPFILES=$(SNMPFILES) \
$(HTTPDFILES) \
$(LWIPERFFILES) \
$(SNTPFILES) \
$(MDNSFILES) \
$(NETBIOSNSFILES) \
$(TFTPFILES) \
$(MQTTFILES)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,9 +6,9 @@
/*
* 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,63 +17,26 @@
* 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/err.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/errno.h"
#if !NO_SYS
/** Table to quickly map an lwIP error (err_t) to a socket error
* by using -err as an index */
static const int err_to_errno_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
ENOMEM, /* ERR_MEM -1 Out of memory error. */
ENOBUFS, /* ERR_BUF -2 Buffer error. */
EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
EINVAL, /* ERR_VAL -6 Illegal value. */
EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
EADDRINUSE, /* ERR_USE -8 Address in use. */
EALREADY, /* ERR_ALREADY -9 Already connecting. */
EISCONN, /* ERR_ISCONN -10 Conn already established.*/
ENOTCONN, /* ERR_CONN -11 Not connected. */
-1, /* ERR_IF -12 Low-level netif error */
ECONNABORTED, /* ERR_ABRT -13 Connection aborted. */
ECONNRESET, /* ERR_RST -14 Connection reset. */
ENOTCONN, /* ERR_CLSD -15 Connection closed. */
EIO /* ERR_ARG -16 Illegal argument. */
};
int
err_to_errno(err_t err)
{
if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_to_errno_table))) {
return EIO;
}
return err_to_errno_table[-err];
}
#endif /* !NO_SYS */
#ifdef LWIP_DEBUG
@@ -87,14 +50,13 @@ static const char *err_strerr[] = {
"Illegal value.", /* ERR_VAL -6 */
"Operation would block.", /* ERR_WOULDBLOCK -7 */
"Address in use.", /* ERR_USE -8 */
"Already connecting.", /* ERR_ALREADY -9 */
"Already connected.", /* ERR_ISCONN -10 */
"Not connected.", /* ERR_CONN -11 */
"Low-level netif error.", /* ERR_IF -12 */
"Connection aborted.", /* ERR_ABRT -13 */
"Connection reset.", /* ERR_RST -14 */
"Connection closed.", /* ERR_CLSD -15 */
"Illegal argument." /* ERR_ARG -16 */
"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 */
};
/**
@@ -106,10 +68,8 @@ static const char *err_strerr[] = {
const char *
lwip_strerr(err_t err)
{
if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_strerr))) {
return "Unknown error.";
}
return err_strerr[-err];
}
#endif /* LWIP_DEBUG */

View File

@@ -2,19 +2,13 @@
* @file
* Network buffer management
*
* @defgroup netbuf Network buffers
* @ingroup netconn
* Network buffer descriptor for @ref netconn. Based on @ref pbuf internally
* to avoid copying data around.\n
* Buffers must not be shared accross multiple threads, all functions except
* netbuf_new() and netbuf_delete() are not thread-safe.
*/
/*
* 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,
@@ -23,21 +17,21 @@
* 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>
*
*/
@@ -52,7 +46,6 @@
#include <string.h>
/**
* @ingroup netbuf
* Create (allocate) and initialize a new netbuf.
* The netbuf doesn't yet contain a packet buffer!
*
@@ -66,13 +59,26 @@ netbuf *netbuf_new(void)
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
if (buf != NULL) {
memset(buf, 0, sizeof(struct netbuf));
buf->p = NULL;
buf->ptr = NULL;
ip_addr_set_any(&buf->addr);
buf->port = 0;
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
#if LWIP_CHECKSUM_ON_COPY
buf->flags = 0;
#endif /* LWIP_CHECKSUM_ON_COPY */
buf->toport_chksum = 0;
#if LWIP_NETBUF_RECVINFO
ip_addr_set_any(&buf->toaddr);
#endif /* LWIP_NETBUF_RECVINFO */
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
return buf;
} else {
return NULL;
}
return buf;
}
/**
* @ingroup netbuf
* Deallocate a netbuf allocated by netbuf_new().
*
* @param buf pointer to a netbuf allocated by netbuf_new()
@@ -90,7 +96,6 @@ netbuf_delete(struct netbuf *buf)
}
/**
* @ingroup netbuf
* Allocate memory for a packet buffer for a given netbuf.
*
* @param buf the netbuf for which to allocate a packet buffer
@@ -118,7 +123,6 @@ netbuf_alloc(struct netbuf *buf, u16_t size)
}
/**
* @ingroup netbuf
* Free the packet buffer included in a netbuf
*
* @param buf pointer to the netbuf which contains the packet buffer to free
@@ -134,7 +138,6 @@ netbuf_free(struct netbuf *buf)
}
/**
* @ingroup netbuf
* Let a netbuf reference existing (non-volatile) data.
*
* @param buf netbuf which should reference the data
@@ -155,14 +158,13 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
buf->ptr = NULL;
return ERR_MEM;
}
((struct pbuf_rom*)buf->p)->payload = dataptr;
buf->p->payload = (void*)dataptr;
buf->p->len = buf->p->tot_len = size;
buf->ptr = buf->p;
return ERR_OK;
}
/**
* @ingroup netbuf
* Chain one netbuf to another (@see pbuf_chain)
*
* @param head the first netbuf
@@ -171,7 +173,7 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
void
netbuf_chain(struct netbuf *head, struct netbuf *tail)
{
LWIP_ERROR("netbuf_chain: invalid head", (head != NULL), return;);
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
pbuf_cat(head->p, tail->p);
head->ptr = head->p;
@@ -179,13 +181,12 @@ netbuf_chain(struct netbuf *head, struct netbuf *tail)
}
/**
* @ingroup netbuf
* Get the data pointer and length of the data inside a netbuf.
*
* @param buf netbuf to get the data from
* @param dataptr pointer to a void pointer where to store the data pointer
* @param len pointer to an u16_t where the length of the data is stored
* @return ERR_OK if the information was retrieved,
* @return ERR_OK if the information was retreived,
* ERR_BUF on error.
*/
err_t
@@ -204,7 +205,6 @@ netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
}
/**
* @ingroup netbuf
* Move the current data pointer of a packet buffer contained in a netbuf
* to the next part.
* The packet buffer itself is not modified.
@@ -217,7 +217,7 @@ netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
s8_t
netbuf_next(struct netbuf *buf)
{
LWIP_ERROR("netbuf_next: invalid buf", (buf != NULL), return -1;);
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;);
if (buf->ptr->next == NULL) {
return -1;
}
@@ -229,7 +229,6 @@ netbuf_next(struct netbuf *buf)
}
/**
* @ingroup netbuf
* Move the current data pointer of a packet buffer contained in a netbuf
* to the beginning of the packet.
* The packet buffer itself is not modified.
@@ -239,7 +238,7 @@ netbuf_next(struct netbuf *buf)
void
netbuf_first(struct netbuf *buf)
{
LWIP_ERROR("netbuf_first: invalid buf", (buf != NULL), return;);
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
buf->ptr = buf->p;
}

View File

@@ -2,12 +2,10 @@
* @file
* API functions for name resolving
*
* @defgroup netdbapi NETDB API
* @ingroup socket
*/
/*
* Redistribution and use in source and binary forms, with or without modification,
* 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,
@@ -16,21 +14,21 @@
* 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: Simon Goldschmidt
*
*/
@@ -46,12 +44,12 @@
#include "lwip/api.h"
#include "lwip/dns.h"
#include <string.h> /* memset */
#include <stdlib.h> /* atoi */
#include <string.h>
#include <stdlib.h>
/** helper struct for gethostbyname_r to access the char* buffer */
struct gethostbyname_r_helper {
ip_addr_t *addr_list[2];
ip_addr_t *addrs;
ip_addr_t addr;
char *aliases;
};
@@ -94,7 +92,6 @@ lwip_gethostbyname(const char *name)
HOSTENT_STORAGE char *s_aliases;
HOSTENT_STORAGE ip_addr_t s_hostent_addr;
HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1];
/* query host IP address */
err = netconn_gethostbyname(name, &addr);
@@ -108,10 +105,7 @@ lwip_gethostbyname(const char *name)
s_hostent_addr = addr;
s_phostent_addr[0] = &s_hostent_addr;
s_phostent_addr[1] = NULL;
strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH);
s_hostname[DNS_MAX_NAME_LENGTH] = 0;
s_hostent.h_name = s_hostname;
s_aliases = NULL;
s_hostent.h_name = (char*)name;
s_hostent.h_aliases = &s_aliases;
s_hostent.h_addrtype = AF_INET;
s_hostent.h_length = sizeof(ip_addr_t);
@@ -120,16 +114,22 @@ lwip_gethostbyname(const char *name)
#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 == %p\n", (void*)s_hostent.h_aliases));
/* h_aliases are always empty */
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]-> == %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 == %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", (void*)s_hostent.h_addr_list));
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++) {
for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx]));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ipaddr_ntoa((ip_addr_t*)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 */
@@ -180,7 +180,7 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
}
/* first thing to do: set *result to nothing */
*result = NULL;
if ((name == NULL) || (ret == NULL) || (buf == NULL)) {
if ((name == NULL) || (ret == NULL) || (buf == 0)) {
/* not all arguments given */
*h_errnop = EINVAL;
return -1;
@@ -197,7 +197,7 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
/* query host IP address */
err = netconn_gethostbyname(name, &h->addr);
err = netconn_gethostbyname(name, &(h->addr));
if (err != ERR_OK) {
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
*h_errnop = HOST_NOT_FOUND;
@@ -209,14 +209,13 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
hostname[namelen] = 0;
/* fill hostent */
h->addr_list[0] = &h->addr;
h->addr_list[1] = NULL;
h->addrs = &(h->addr);
h->aliases = NULL;
ret->h_name = hostname;
ret->h_aliases = &h->aliases;
ret->h_name = (char*)hostname;
ret->h_aliases = &(h->aliases);
ret->h_addrtype = AF_INET;
ret->h_length = sizeof(ip_addr_t);
ret->h_addr_list = (char**)&h->addr_list;
ret->h_addr_list = (char**)&(h->addrs);
/* set result != NULL */
*result = ret;
@@ -258,12 +257,10 @@ lwip_freeaddrinfo(struct addrinfo *ai)
*
* @param nodename descriptive name or address string of the host
* (may be NULL -> local address)
* @param servname port number as string of NULL
* @param servname port number as string of NULL
* @param hints structure containing input values that set socktype and protocol
* @param res pointer to a pointer where to store the result (set to NULL on failure)
* @return 0 on success, non-zero on failure
*
* @todo: implement AI_V4MAPPED, AI_ADDRCONFIG
*/
int
lwip_getaddrinfo(const char *nodename, const char *servname,
@@ -272,11 +269,10 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
err_t err;
ip_addr_t addr;
struct addrinfo *ai;
struct sockaddr_storage *sa = NULL;
struct sockaddr_in *sa = NULL;
int port_nr = 0;
size_t total_size;
size_t namelen = 0;
int ai_family;
if (res == NULL) {
return EAI_FAIL;
@@ -286,25 +282,9 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
return EAI_NONAME;
}
if (hints != NULL) {
ai_family = hints->ai_family;
if ((ai_family != AF_UNSPEC)
#if LWIP_IPV4
&& (ai_family != AF_INET)
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
&& (ai_family != AF_INET6)
#endif /* LWIP_IPV6 */
) {
return EAI_FAMILY;
}
} else {
ai_family = AF_UNSPEC;
}
if (servname != NULL) {
/* service name specified: convert to port number
* @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */
* @todo?: currently, only ASCII integers (port numbers) are supported! */
port_nr = atoi(servname);
if ((port_nr <= 0) || (port_nr > 0xffff)) {
return EAI_SERVICE;
@@ -313,49 +293,19 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
if (nodename != NULL) {
/* service location specified, try to resolve */
if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) {
/* no DNS lookup, just parse for an address string */
if (!ipaddr_aton(nodename, &addr)) {
return EAI_NONAME;
}
#if LWIP_IPV4 && LWIP_IPV6
if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) ||
(IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) {
return EAI_NONAME;
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
} else {
#if LWIP_IPV4 && LWIP_IPV6
/* AF_UNSPEC: prefer IPv4 */
u8_t type = NETCONN_DNS_IPV4_IPV6;
if (ai_family == AF_INET) {
type = NETCONN_DNS_IPV4;
} else if (ai_family == AF_INET6) {
type = NETCONN_DNS_IPV6;
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
err = netconn_gethostbyname_addrtype(nodename, &addr, type);
if (err != ERR_OK) {
return EAI_FAIL;
}
err = netconn_gethostbyname(nodename, &addr);
if (err != ERR_OK) {
return EAI_FAIL;
}
} else {
/* service location specified, use loopback address */
if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) {
ip_addr_set_any(ai_family == AF_INET6, &addr);
} else {
ip_addr_set_loopback(ai_family == AF_INET6, &addr);
}
ip_addr_set_loopback(&addr);
}
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage);
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
if (nodename != NULL) {
namelen = strlen(nodename);
if (namelen > DNS_MAX_NAME_LENGTH) {
/* invalid name length */
return EAI_FAIL;
}
LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size);
LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
total_size += namelen + 1;
}
/* If this fails, please report to lwip-devel! :-) */
@@ -363,34 +313,18 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
total_size <= NETDB_ELEM_SIZE);
ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
if (ai == NULL) {
return EAI_MEMORY;
goto memerr;
}
memset(ai, 0, total_size);
/* cast through void* to get rid of alignment warnings */
sa = (struct sockaddr_storage *)(void*)((u8_t*)ai + sizeof(struct addrinfo));
if (IP_IS_V6_VAL(addr)) {
#if LWIP_IPV6
struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)sa;
/* set up sockaddr */
inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr));
sa6->sin6_family = AF_INET6;
sa6->sin6_len = sizeof(struct sockaddr_in6);
sa6->sin6_port = lwip_htons((u16_t)port_nr);
ai->ai_family = AF_INET6;
#endif /* LWIP_IPV6 */
} else {
#if LWIP_IPV4
struct sockaddr_in *sa4 = (struct sockaddr_in*)sa;
/* set up sockaddr */
inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr));
sa4->sin_family = AF_INET;
sa4->sin_len = sizeof(struct sockaddr_in);
sa4->sin_port = lwip_htons((u16_t)port_nr);
ai->ai_family = AF_INET;
#endif /* LWIP_IPV4 */
}
sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
/* set up sockaddr */
inet_addr_from_ipaddr(&sa->sin_addr, &addr);
sa->sin_family = AF_INET;
sa->sin_len = sizeof(struct sockaddr_in);
sa->sin_port = htons((u16_t)port_nr);
/* set up addrinfo */
ai->ai_family = AF_INET;
if (hints != NULL) {
/* copy socktype & protocol from hints if specified */
ai->ai_socktype = hints->ai_socktype;
@@ -398,16 +332,21 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
}
if (nodename != NULL) {
/* copy nodename to canonname if specified */
ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
MEMCPY(ai->ai_canonname, nodename, namelen);
ai->ai_canonname[namelen] = 0;
}
ai->ai_addrlen = sizeof(struct sockaddr_storage);
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_addr = (struct sockaddr*)sa;
*res = ai;
return 0;
memerr:
if (ai != NULL) {
memp_free(MEMP_NETDB, ai);
}
return EAI_MEMORY;
}
#endif /* LWIP_DNS && LWIP_SOCKET */

View File

@@ -2,17 +2,10 @@
* @file
* Network Interface Sequential API module
*
* @defgroup netifapi NETIF API
* @ingroup sequential_api
* Thread-safe functions to be called from non-TCPIP threads
*
* @defgroup netifapi_netif NETIF related
* @ingroup netifapi
* To be called from non-TCPIP threads
*/
/*
* Redistribution and use in source and binary forms, with or without modification,
* 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,
@@ -21,21 +14,21 @@
* 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.
*
*
*/
#include "lwip/opt.h"
@@ -43,79 +36,59 @@
#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
#include "lwip/netifapi.h"
#include "lwip/memp.h"
#include "lwip/priv/tcpip_priv.h"
#define NETIFAPI_VAR_REF(name) API_VAR_REF(name)
#define NETIFAPI_VAR_DECLARE(name) API_VAR_DECLARE(struct netifapi_msg, name)
#define NETIFAPI_VAR_ALLOC(name) API_VAR_ALLOC(struct netifapi_msg, MEMP_NETIFAPI_MSG, name, ERR_MEM)
#define NETIFAPI_VAR_FREE(name) API_VAR_FREE(MEMP_NETIFAPI_MSG, name)
#include "lwip/tcpip.h"
/**
* Call netif_add() inside the tcpip_thread context.
*/
static err_t
netifapi_do_netif_add(struct tcpip_api_call_data *m)
void
do_netifapi_netif_add(struct netifapi_msg_msg *msg)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct netifapi_msg */
struct netifapi_msg *msg = (struct netifapi_msg*)(void*)m;
if (!netif_add( msg->netif,
#if LWIP_IPV4
API_EXPR_REF(msg->msg.add.ipaddr),
API_EXPR_REF(msg->msg.add.netmask),
API_EXPR_REF(msg->msg.add.gw),
#endif /* LWIP_IPV4 */
msg->msg.add.ipaddr,
msg->msg.add.netmask,
msg->msg.add.gw,
msg->msg.add.state,
msg->msg.add.init,
msg->msg.add.input)) {
return ERR_IF;
msg->err = ERR_IF;
} else {
return ERR_OK;
msg->err = ERR_OK;
}
TCPIP_NETIFAPI_ACK(msg);
}
#if LWIP_IPV4
/**
* Call netif_set_addr() inside the tcpip_thread context.
*/
static err_t
netifapi_do_netif_set_addr(struct tcpip_api_call_data *m)
void
do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct netifapi_msg */
struct netifapi_msg *msg = (struct netifapi_msg*)(void*)m;
netif_set_addr( msg->netif,
API_EXPR_REF(msg->msg.add.ipaddr),
API_EXPR_REF(msg->msg.add.netmask),
API_EXPR_REF(msg->msg.add.gw));
return ERR_OK;
msg->msg.add.ipaddr,
msg->msg.add.netmask,
msg->msg.add.gw);
msg->err = ERR_OK;
TCPIP_NETIFAPI_ACK(msg);
}
#endif /* LWIP_IPV4 */
/**
* Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
* tcpip_thread context.
*/
static err_t
netifapi_do_netif_common(struct tcpip_api_call_data *m)
void
do_netifapi_netif_common(struct netifapi_msg_msg *msg)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct netifapi_msg */
struct netifapi_msg *msg = (struct netifapi_msg*)(void*)m;
if (msg->msg.common.errtfunc != NULL) {
return msg->msg.common.errtfunc(msg->netif);
msg->err = msg->msg.common.errtfunc(msg->netif);
} else {
msg->err = ERR_OK;
msg->msg.common.voidfunc(msg->netif);
return ERR_OK;
}
TCPIP_NETIFAPI_ACK(msg);
}
/**
* @ingroup netifapi_netif
* Call netif_add() in a thread-safe way by running that function inside the
* tcpip_thread context.
*
@@ -123,44 +96,27 @@ netifapi_do_netif_common(struct tcpip_api_call_data *m)
*/
err_t
netifapi_netif_add(struct netif *netif,
#if LWIP_IPV4
const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw,
#endif /* LWIP_IPV4 */
void *state, netif_init_fn init, netif_input_fn input)
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw,
void *state,
netif_init_fn init,
netif_input_fn input)
{
err_t err;
NETIFAPI_VAR_DECLARE(msg);
NETIFAPI_VAR_ALLOC(msg);
#if LWIP_IPV4
if (ipaddr == NULL) {
ipaddr = IP4_ADDR_ANY4;
}
if (netmask == NULL) {
netmask = IP4_ADDR_ANY4;
}
if (gw == NULL) {
gw = IP4_ADDR_ANY4;
}
#endif /* LWIP_IPV4 */
NETIFAPI_VAR_REF(msg).netif = netif;
#if LWIP_IPV4
NETIFAPI_VAR_REF(msg).msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr);
NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask);
NETIFAPI_VAR_REF(msg).msg.add.gw = NETIFAPI_VAR_REF(gw);
#endif /* LWIP_IPV4 */
NETIFAPI_VAR_REF(msg).msg.add.state = state;
NETIFAPI_VAR_REF(msg).msg.add.init = init;
NETIFAPI_VAR_REF(msg).msg.add.input = input;
err = tcpip_api_call(netifapi_do_netif_add, &API_VAR_REF(msg).call);
NETIFAPI_VAR_FREE(msg);
return err;
struct netifapi_msg msg;
msg.function = do_netifapi_netif_add;
msg.msg.netif = netif;
msg.msg.msg.add.ipaddr = ipaddr;
msg.msg.msg.add.netmask = netmask;
msg.msg.msg.add.gw = gw;
msg.msg.msg.add.state = state;
msg.msg.msg.add.init = init;
msg.msg.msg.add.input = input;
TCPIP_NETIFAPI(&msg);
return msg.msg.err;
}
#if LWIP_IPV4
/**
* @ingroup netifapi_netif
* Call netif_set_addr() in a thread-safe way by running that function inside the
* tcpip_thread context.
*
@@ -168,33 +124,19 @@ netifapi_netif_add(struct netif *netif,
*/
err_t
netifapi_netif_set_addr(struct netif *netif,
const ip4_addr_t *ipaddr,
const ip4_addr_t *netmask,
const ip4_addr_t *gw)
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw)
{
err_t err;
NETIFAPI_VAR_DECLARE(msg);
NETIFAPI_VAR_ALLOC(msg);
if (ipaddr == NULL) {
ipaddr = IP4_ADDR_ANY4;
}
if (netmask == NULL) {
netmask = IP4_ADDR_ANY4;
}
if (gw == NULL) {
gw = IP4_ADDR_ANY4;
}
NETIFAPI_VAR_REF(msg).netif = netif;
NETIFAPI_VAR_REF(msg).msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr);
NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask);
NETIFAPI_VAR_REF(msg).msg.add.gw = NETIFAPI_VAR_REF(gw);
err = tcpip_api_call(netifapi_do_netif_set_addr, &API_VAR_REF(msg).call);
NETIFAPI_VAR_FREE(msg);
return err;
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;
}
#endif /* LWIP_IPV4 */
/**
* call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
@@ -206,16 +148,13 @@ err_t
netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
netifapi_errt_fn errtfunc)
{
err_t err;
NETIFAPI_VAR_DECLARE(msg);
NETIFAPI_VAR_ALLOC(msg);
NETIFAPI_VAR_REF(msg).netif = netif;
NETIFAPI_VAR_REF(msg).msg.common.voidfunc = voidfunc;
NETIFAPI_VAR_REF(msg).msg.common.errtfunc = errtfunc;
err = tcpip_api_call(netifapi_do_netif_common, &API_VAR_REF(msg).call);
NETIFAPI_VAR_FREE(msg);
return err;
struct netifapi_msg msg;
msg.function = do_netifapi_netif_common;
msg.msg.netif = netif;
msg.msg.msg.common.voidfunc = voidfunc;
msg.msg.msg.common.errtfunc = errtfunc;
TCPIP_NETIFAPI(&msg);
return msg.msg.err;
}
#endif /* LWIP_NETIF_API */

File diff suppressed because it is too large Load Diff

View File

@@ -40,20 +40,14 @@
#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
#include "lwip/priv/tcpip_priv.h"
#include "lwip/sys.h"
#include "lwip/memp.h"
#include "lwip/mem.h"
#include "lwip/init.h"
#include "lwip/ip.h"
#include "lwip/pbuf.h"
#include "lwip/etharp.h"
#include "netif/ethernet.h"
#define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name)
#define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name)
#define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM)
#define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name)
#include "lwip/tcpip.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "netif/ppp_oe.h"
/* global variables */
static tcpip_init_done_fn tcpip_init_done;
@@ -65,13 +59,6 @@ static sys_mbox_t mbox;
sys_mutex_t lock_tcpip_core;
#endif /* LWIP_TCPIP_CORE_LOCKING */
#if LWIP_TIMERS
/* wait for a message, timeouts are processed while waiting */
#define TCPIP_MBOX_FETCH(mbox, msg) sys_timeouts_mbox_fetch(mbox, msg)
#else /* LWIP_TIMERS */
/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */
#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg)
#endif /* LWIP_TIMERS */
/**
* The main lwIP thread. This thread has exclusive access to lwIP core functions
@@ -98,35 +85,39 @@ tcpip_thread(void *arg)
UNLOCK_TCPIP_CORE();
LWIP_TCPIP_THREAD_ALIVE();
/* wait for a message, timeouts are processed while waiting */
TCPIP_MBOX_FETCH(&mbox, (void **)&msg);
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
LOCK_TCPIP_CORE();
if (msg == NULL) {
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
continue;
}
switch (msg->type) {
#if !LWIP_TCPIP_CORE_LOCKING
#if LWIP_NETCONN
case TCPIP_MSG_API:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
msg->msg.api_msg.function(msg->msg.api_msg.msg);
msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
break;
case TCPIP_MSG_API_CALL:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg));
msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg);
sys_sem_signal(msg->msg.api_call.sem);
break;
#endif /* !LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETCONN */
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
case TCPIP_MSG_INPKT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif);
#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_ETHERNET */
{
ip_input(msg->msg.inp.p, msg->msg.inp.netif);
}
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
break;
#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
#if LWIP_NETIF_API
case TCPIP_MSG_NETIFAPI:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
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);
@@ -137,7 +128,7 @@ tcpip_thread(void *arg)
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
#endif /* LWIP_TCPIP_TIMEOUT */
case TCPIP_MSG_CALLBACK:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
@@ -161,25 +152,34 @@ tcpip_thread(void *arg)
/**
* Pass a received packet to tcpip_thread for input processing
*
* @param p the received packet
* @param p the received packet, p->payload pointing to the Ethernet header or
* 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
* @param input_fn input function to call
*/
err_t
tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
tcpip_input(struct pbuf *p, struct netif *inp)
{
#if LWIP_TCPIP_CORE_LOCKING_INPUT
err_t ret;
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp));
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp));
LOCK_TCPIP_CORE();
ret = input_fn(p, inp);
#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;
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
if (!sys_mbox_valid(&mbox)) {
return ERR_VAL;
}
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
if (msg == NULL) {
return ERR_MEM;
@@ -188,7 +188,6 @@ tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
msg->type = TCPIP_MSG_INPKT;
msg->msg.inp.p = p;
msg->msg.inp.netif = inp;
msg->msg.inp.input_fn = input_fn;
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
return ERR_MEM;
@@ -197,35 +196,13 @@ tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
}
/**
* @ingroup lwip_os
* Pass a received packet to tcpip_thread for input processing with
* ethernet_input or ip_input. Don't call directly, pass to netif_add()
* and call netif->input().
*
* @param p the received packet, p->payload pointing to the Ethernet header or
* 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_ETHERNET
if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
return tcpip_inpkt(p, inp, ethernet_input);
} else
#endif /* LWIP_ETHERNET */
return tcpip_inpkt(p, inp, ip_input);
}
/**
* Call a specific function in the thread context of
* tcpip_thread for easy access synchronization.
* A function called in that way may access lwIP core code
* without fearing concurrent access.
*
* @param function the function to call
* @param f the function to call
* @param ctx parameter passed to f
* @param block 1 to block until the request is posted, 0 to non-blocking mode
* @return ERR_OK if the function was called, another err_t if not
@@ -235,32 +212,33 @@ tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
{
struct tcpip_msg *msg;
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(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.function = function;
msg->msg.cb.ctx = ctx;
if (block) {
sys_mbox_post(&mbox, msg);
} else {
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_API, 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_CALLBACK;
msg->msg.cb.function = function;
msg->msg.cb.ctx = ctx;
if (block) {
sys_mbox_post(&mbox, msg);
} else {
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_API, msg);
return ERR_MEM;
}
}
return ERR_OK;
}
return ERR_OK;
return ERR_VAL;
}
#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
#if LWIP_TCPIP_TIMEOUT
/**
* call sys_timeout in tcpip_thread
*
* @param msecs time in milliseconds for timeout
* @param msec time in milliseconds for timeout
* @param h function to be called on timeout
* @param arg argument to pass to timeout function h
* @return ERR_MEM on memory error, ERR_OK otherwise
@@ -270,24 +248,26 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
{
struct tcpip_msg *msg;
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
msg->type = TCPIP_MSG_TIMEOUT;
msg->msg.tmo.msecs = msecs;
msg->msg.tmo.h = h;
msg->msg.tmo.arg = arg;
sys_mbox_post(&mbox, msg);
return ERR_OK;
}
msg->type = TCPIP_MSG_TIMEOUT;
msg->msg.tmo.msecs = msecs;
msg->msg.tmo.h = h;
msg->msg.tmo.arg = arg;
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
@@ -297,111 +277,125 @@ tcpip_untimeout(sys_timeout_handler h, void *arg)
{
struct tcpip_msg *msg;
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
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;
}
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 && LWIP_TIMERS */
#endif /* LWIP_TCPIP_TIMEOUT */
#if LWIP_NETCONN
/**
* Sends a message to TCPIP thread to call a function. Caller thread blocks on
* on a provided semaphore, which ist NOT automatically signalled by TCPIP thread,
* this has to be done by the user.
* It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way
* with least runtime overhead.
* Call the lower part of a netconn_* function
* This function is then running in the thread context
* of tcpip_thread and has exclusive access to lwIP core code.
*
* @param fn function to be called from TCPIP thread
* @param apimsg argument to API function
* @param sem semaphore to wait on
* @param apimsg a struct containing the function to call and its parameters
* @return ERR_OK if the function was called, another err_t if not
*/
err_t
tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem)
tcpip_apimsg(struct api_msg *apimsg)
{
#if LWIP_TCPIP_CORE_LOCKING
LWIP_UNUSED_ARG(sem);
LOCK_TCPIP_CORE();
fn(apimsg);
UNLOCK_TCPIP_CORE();
return ERR_OK;
#else /* LWIP_TCPIP_CORE_LOCKING */
TCPIP_MSG_VAR_DECLARE(msg);
LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem));
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
TCPIP_MSG_VAR_ALLOC(msg);
TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API;
TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn;
TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg;
sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg));
sys_arch_sem_wait(sem, 0);
TCPIP_MSG_VAR_FREE(msg);
return ERR_OK;
#endif /* LWIP_TCPIP_CORE_LOCKING */
struct tcpip_msg msg;
#ifdef LWIP_DEBUG
/* catch functions that don't set err */
apimsg->msg.err = ERR_VAL;
#endif
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 apimsg->msg.err;
}
return ERR_VAL;
}
#if LWIP_TCPIP_CORE_LOCKING
/**
* Synchronously calls function in TCPIP thread and waits for its completion.
* It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or
* LWIP_NETCONN_SEM_PER_THREAD.
* If not, a semaphore is created and destroyed on every call which is usually
* an expensive/slow operation.
* @param fn Function to call
* @param call Call parameters
* @return Return value from tcpip_api_call_fn
* Call the lower part of a netconn_* function
* This function has exclusive access to lwIP core code by locking it
* before the function is called.
*
* @param apimsg a struct containing the function to call and its parameters
* @return ERR_OK (only for compatibility fo tcpip_apimsg())
*/
err_t
tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
tcpip_apimsg_lock(struct api_msg *apimsg)
{
#if LWIP_TCPIP_CORE_LOCKING
err_t err;
#ifdef LWIP_DEBUG
/* catch functions that don't set err */
apimsg->msg.err = ERR_VAL;
#endif
LOCK_TCPIP_CORE();
err = fn(call);
apimsg->function(&(apimsg->msg));
UNLOCK_TCPIP_CORE();
return err;
#else /* LWIP_TCPIP_CORE_LOCKING */
TCPIP_MSG_VAR_DECLARE(msg);
return apimsg->msg.err;
#if !LWIP_NETCONN_SEM_PER_THREAD
err_t err = sys_sem_new(&call->sem, 0);
if (err != ERR_OK) {
return err;
}
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
TCPIP_MSG_VAR_ALLOC(msg);
TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL;
TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call;
TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn;
#if LWIP_NETCONN_SEM_PER_THREAD
TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET();
#else /* LWIP_NETCONN_SEM_PER_THREAD */
TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem;
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg));
sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0);
TCPIP_MSG_VAR_FREE(msg);
#if !LWIP_NETCONN_SEM_PER_THREAD
sys_sem_free(&call->sem);
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
return call->err;
#endif /* LWIP_TCPIP_CORE_LOCKING */
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETCONN */
#if LWIP_NETIF_API
#if !LWIP_TCPIP_CORE_LOCKING
/**
* Much like tcpip_apimsg, but calls the lower part of a netifapi_*
* function.
*
* @param netifapimsg a struct containing the function to call and its parameters
* @return error code given back by the function that was called
*/
err_t
tcpip_netifapi(struct netifapi_msg* netifapimsg)
{
struct tcpip_msg msg;
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);
return netifapimsg->msg.err;
}
return ERR_VAL;
}
#else /* !LWIP_TCPIP_CORE_LOCKING */
/**
* Call the lower part of a netifapi_* function
* This function has exclusive access to lwIP core code by locking it
* before the function is called.
*
* @param netifapimsg a struct containing the function to call and its parameters
* @return ERR_OK (only for compatibility fo tcpip_netifapi())
*/
err_t
tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
{
LOCK_TCPIP_CORE();
netifapimsg->function(&(netifapimsg->msg));
UNLOCK_TCPIP_CORE();
return netifapimsg->msg.err;
}
#endif /* !LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETIF_API */
/**
* Allocate a structure for a static callback message and initialize it.
@@ -411,8 +405,7 @@ tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *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_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) {
@@ -429,8 +422,7 @@ tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
*
* @param msg the message to free
*/
void
tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
{
memp_free(MEMP_TCPIP_MSG_API, msg);
}
@@ -445,12 +437,13 @@ tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
err_t
tcpip_trycallback(struct tcpip_callback_msg* msg)
{
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
if (!sys_mbox_valid(&mbox)) {
return ERR_VAL;
}
return sys_mbox_trypost(&mbox, msg);
}
/**
* @ingroup lwip_os
* Initialize this module:
* - initialize all sub modules
* - start the tcpip_thread
@@ -465,11 +458,11 @@ tcpip_init(tcpip_init_done_fn initfunc, void *arg)
tcpip_init_done = initfunc;
tcpip_init_done_arg = arg;
if (sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
}
#if LWIP_TCPIP_CORE_LOCKING
if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
LWIP_ASSERT("failed to create lock_tcpip_core", 0);
}
#endif /* LWIP_TCPIP_CORE_LOCKING */

View File

@@ -1,179 +0,0 @@
/*
* Copyright (c) 2001-2003 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/apps/httpd_opts.h"
#include "lwip/def.h"
#include "lwip/apps/fs.h"
#include "fsdata.h"
#include <string.h>
#if HTTPD_USE_CUSTOM_FSDATA
#include "fsdata_custom.c"
#else /* HTTPD_USE_CUSTOM_FSDATA */
#include "fsdata.c"
#endif /* HTTPD_USE_CUSTOM_FSDATA */
/*-----------------------------------------------------------------------------------*/
#if LWIP_HTTPD_CUSTOM_FILES
int fs_open_custom(struct fs_file *file, const char *name);
void fs_close_custom(struct fs_file *file);
#if LWIP_HTTPD_FS_ASYNC_READ
u8_t fs_canread_custom(struct fs_file *file);
u8_t fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg);
int fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg);
#else /* LWIP_HTTPD_FS_ASYNC_READ */
int fs_read_custom(struct fs_file *file, char *buffer, int count);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
#endif /* LWIP_HTTPD_CUSTOM_FILES */
/*-----------------------------------------------------------------------------------*/
err_t
fs_open(struct fs_file *file, const char *name)
{
const struct fsdata_file *f;
if ((file == NULL) || (name == NULL)) {
return ERR_ARG;
}
#if LWIP_HTTPD_CUSTOM_FILES
if (fs_open_custom(file, name)) {
file->is_custom_file = 1;
return ERR_OK;
}
file->is_custom_file = 0;
#endif /* LWIP_HTTPD_CUSTOM_FILES */
for (f = FS_ROOT; f != NULL; f = f->next) {
if (!strcmp(name, (const char *)f->name)) {
file->data = (const char *)f->data;
file->len = f->len;
file->index = f->len;
file->pextension = NULL;
file->flags = f->flags;
#if HTTPD_PRECALCULATED_CHECKSUM
file->chksum_count = f->chksum_count;
file->chksum = f->chksum;
#endif /* HTTPD_PRECALCULATED_CHECKSUM */
#if LWIP_HTTPD_FILE_STATE
file->state = fs_state_init(file, name);
#endif /* #if LWIP_HTTPD_FILE_STATE */
return ERR_OK;
}
}
/* file not found */
return ERR_VAL;
}
/*-----------------------------------------------------------------------------------*/
void
fs_close(struct fs_file *file)
{
#if LWIP_HTTPD_CUSTOM_FILES
if (file->is_custom_file) {
fs_close_custom(file);
}
#endif /* LWIP_HTTPD_CUSTOM_FILES */
#if LWIP_HTTPD_FILE_STATE
fs_state_free(file, file->state);
#endif /* #if LWIP_HTTPD_FILE_STATE */
LWIP_UNUSED_ARG(file);
}
/*-----------------------------------------------------------------------------------*/
#if LWIP_HTTPD_DYNAMIC_FILE_READ
#if LWIP_HTTPD_FS_ASYNC_READ
int
fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg)
#else /* LWIP_HTTPD_FS_ASYNC_READ */
int
fs_read(struct fs_file *file, char *buffer, int count)
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
{
int read;
if(file->index == file->len) {
return FS_READ_EOF;
}
#if LWIP_HTTPD_FS_ASYNC_READ
LWIP_UNUSED_ARG(callback_fn);
LWIP_UNUSED_ARG(callback_arg);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
#if LWIP_HTTPD_CUSTOM_FILES
if (file->is_custom_file) {
#if LWIP_HTTPD_FS_ASYNC_READ
return fs_read_async_custom(file, buffer, count, callback_fn, callback_arg);
#else /* LWIP_HTTPD_FS_ASYNC_READ */
return fs_read_custom(file, buffer, count);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
}
#endif /* LWIP_HTTPD_CUSTOM_FILES */
read = file->len - file->index;
if(read > count) {
read = count;
}
MEMCPY(buffer, (file->data + file->index), read);
file->index += read;
return(read);
}
#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
/*-----------------------------------------------------------------------------------*/
#if LWIP_HTTPD_FS_ASYNC_READ
int
fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg)
{
if (file != NULL) {
#if LWIP_HTTPD_FS_ASYNC_READ
#if LWIP_HTTPD_CUSTOM_FILES
if (!fs_canread_custom(file)) {
if (fs_wait_read_custom(file, callback_fn, callback_arg)) {
return 0;
}
}
#else /* LWIP_HTTPD_CUSTOM_FILES */
LWIP_UNUSED_ARG(callback_fn);
LWIP_UNUSED_ARG(callback_arg);
#endif /* LWIP_HTTPD_CUSTOM_FILES */
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
}
return 1;
}
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
/*-----------------------------------------------------------------------------------*/
int
fs_bytes_left(struct fs_file *file)
{
return file->len - file->index;
}

View File

@@ -1,21 +0,0 @@
<html>
<head><title>lwIP - A Lightweight TCP/IP Stack</title></head>
<body bgcolor="white" text="black">
<table width="100%">
<tr valign="top"><td width="80">
<a href="http://www.sics.se/"><img src="/img/sics.gif"
border="0" alt="SICS logo" title="SICS logo"></a>
</td><td width="500">
<h1>lwIP - A Lightweight TCP/IP Stack</h1>
<h2>404 - Page not found</h2>
<p>
Sorry, the page you are requesting was not found on this
server.
</p>
</td><td>
&nbsp;
</td></tr>
</table>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 724 B

View File

@@ -1,47 +0,0 @@
<html>
<head><title>lwIP - A Lightweight TCP/IP Stack</title></head>
<body bgcolor="white" text="black">
<table width="100%">
<tr valign="top"><td width="80">
<a href="http://www.sics.se/"><img src="/img/sics.gif"
border="0" alt="SICS logo" title="SICS logo"></a>
</td><td width="500">
<h1>lwIP - A Lightweight TCP/IP Stack</h1>
<p>
The web page you are watching was served by a simple web
server running on top of the lightweight TCP/IP stack <a
href="http://www.sics.se/~adam/lwip/">lwIP</a>.
</p>
<p>
lwIP is an open source implementation of the TCP/IP
protocol suite that was originally written by <a
href="http://www.sics.se/~adam/lwip/">Adam Dunkels
of the Swedish Institute of Computer Science</a> but now is
being actively developed by a team of developers
distributed world-wide. Since it's release, lwIP has
spurred a lot of interest and has been ported to several
platforms and operating systems. lwIP can be used either
with or without an underlying OS.
</p>
<p>
The focus of the lwIP TCP/IP implementation is to reduce
the RAM usage while still having a full scale TCP. This
makes lwIP suitable for use in embedded systems with tens
of kilobytes of free RAM and room for around 40 kilobytes
of code ROM.
</p>
<p>
More information about lwIP can be found at the lwIP
homepage at <a
href="http://savannah.nongnu.org/projects/lwip/">http://savannah.nongnu.org/projects/lwip/</a>
or at the lwIP wiki at <a
href="http://lwip.wikia.com/">http://lwip.wikia.com/</a>.
</p>
</td><td>
&nbsp;
</td></tr>
</table>
</body>
</html>

View File

@@ -1,298 +0,0 @@
#include "lwip/apps/fs.h"
#include "lwip/def.h"
#include "fsdata.h"
#define file_NULL (struct fsdata_file *) NULL
static const unsigned int dummy_align__img_sics_gif = 0;
static const unsigned char data__img_sics_gif[] = {
/* /img/sics.gif (14 chars) */
0x2f,0x69,0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x00,0x00,0x00,
/* HTTP header */
/* "HTTP/1.0 200 OK
" (17 bytes) */
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,
0x0a,
/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip)
" (63 bytes) */
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33,
0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,
0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,
0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
/* "Content-type: image/gif
" (27 bytes) */
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x69,0x6d,
0x61,0x67,0x65,0x2f,0x67,0x69,0x66,0x0d,0x0a,0x0d,0x0a,
/* raw file data (724 bytes) */
0x47,0x49,0x46,0x38,0x39,0x61,0x46,0x00,0x22,0x00,0xa5,0x00,0x00,0xd9,0x2b,0x39,
0x6a,0x6a,0x6a,0xbf,0xbf,0xbf,0x93,0x93,0x93,0x0f,0x0f,0x0f,0xb0,0xb0,0xb0,0xa6,
0xa6,0xa6,0x80,0x80,0x80,0x76,0x76,0x76,0x1e,0x1e,0x1e,0x9d,0x9d,0x9d,0x2e,0x2e,
0x2e,0x49,0x49,0x49,0x54,0x54,0x54,0x8a,0x8a,0x8a,0x60,0x60,0x60,0xc6,0xa6,0x99,
0xbd,0xb5,0xb2,0xc2,0xab,0xa1,0xd9,0x41,0x40,0xd5,0x67,0x55,0xc0,0xb0,0xaa,0xd5,
0x5e,0x4e,0xd6,0x50,0x45,0xcc,0x93,0x7d,0xc8,0xa1,0x90,0xce,0x8b,0x76,0xd2,0x7b,
0x65,0xd1,0x84,0x6d,0xc9,0x99,0x86,0x3a,0x3a,0x3a,0x00,0x00,0x00,0xb8,0xb8,0xb8,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2c,0x00,0x00,
0x00,0x00,0x46,0x00,0x22,0x00,0x00,0x06,0xfe,0x40,0x90,0x70,0x48,0x2c,0x1a,0x8f,
0xc8,0xa4,0x72,0xc9,0x6c,0x3a,0x9f,0xd0,0xa8,0x74,0x4a,0xad,0x5a,0xaf,0xd8,0xac,
0x76,0xa9,0x40,0x04,0xbe,0x83,0xe2,0x60,0x3c,0x50,0x20,0x0d,0x8e,0x6f,0x00,0x31,
0x28,0x1c,0x0d,0x07,0xb5,0xc3,0x60,0x75,0x24,0x3e,0xf8,0xfc,0x87,0x11,0x06,0xe9,
0x3d,0x46,0x07,0x0b,0x7a,0x7a,0x7c,0x43,0x06,0x1e,0x84,0x78,0x0b,0x07,0x6e,0x51,
0x01,0x8a,0x84,0x08,0x7e,0x79,0x80,0x87,0x89,0x91,0x7a,0x93,0x0a,0x04,0x99,0x78,
0x96,0x4f,0x03,0x9e,0x79,0x01,0x94,0x9f,0x43,0x9c,0xa3,0xa4,0x05,0x77,0xa3,0xa0,
0x4e,0x98,0x79,0x0b,0x1e,0x83,0xa4,0xa6,0x1f,0x96,0x05,0x9d,0xaa,0x78,0x01,0x07,
0x84,0x04,0x1e,0x1e,0xbb,0xb8,0x51,0x84,0x0e,0x43,0x05,0x07,0x77,0xa5,0x7f,0x42,
0xb1,0xb2,0x01,0x63,0x08,0x0d,0xbb,0x01,0x0c,0x7a,0x0d,0x44,0x0e,0xd8,0xaf,0x4c,
0x05,0x7a,0x04,0x47,0x07,0x07,0xb7,0x80,0xa2,0xe1,0x7d,0x44,0x05,0x01,0x04,0x01,
0xd0,0xea,0x87,0x93,0x4f,0xe0,0x9a,0x49,0xce,0xd8,0x79,0x04,0x66,0x20,0x15,0x10,
0x10,0x11,0x92,0x29,0x80,0xb6,0xc0,0x91,0x15,0x45,0x1e,0x90,0x19,0x71,0x46,0xa8,
0x5c,0x04,0x0e,0x00,0x22,0x4e,0xe8,0x40,0x24,0x9f,0x3e,0x04,0x06,0xa7,0x58,0xd4,
0x93,0xa0,0x1c,0x91,0x3f,0xe8,0xf0,0x88,0x03,0xb1,0x21,0xa2,0x49,0x00,0x19,0x86,
0xfc,0x52,0x44,0xe0,0x01,0x9d,0x29,0x21,0x15,0x25,0x50,0xf7,0x67,0x25,0x1e,0x06,
0xfd,0x4e,0x9a,0xb4,0x90,0xac,0x15,0xfa,0xcb,0x52,0x53,0x1e,0x8c,0xf2,0xf8,0x07,
0x92,0x2d,0x08,0x3a,0x4d,0x12,0x49,0x95,0x49,0xdb,0x14,0x04,0xc4,0x14,0x85,0x29,
0xaa,0xe7,0x01,0x08,0xa4,0x49,0x01,0x14,0x51,0xe0,0x53,0x91,0xd5,0x29,0x06,0x1a,
0x64,0x02,0xf4,0xc7,0x81,0x9e,0x05,0x20,0x22,0x64,0xa5,0x30,0xae,0xab,0x9e,0x97,
0x53,0xd8,0xb9,0xfd,0x50,0xef,0x93,0x02,0x42,0x74,0x34,0xe8,0x9c,0x20,0x21,0xc9,
0x01,0x68,0x78,0xe6,0x55,0x29,0x20,0x56,0x4f,0x4c,0x40,0x51,0x71,0x82,0xc0,0x70,
0x21,0x22,0x85,0xbe,0x4b,0x1c,0x44,0x05,0xea,0xa4,0x01,0xbf,0x22,0xb5,0xf0,0x1c,
0x06,0x51,0x38,0x8f,0xe0,0x22,0xec,0x18,0xac,0x39,0x22,0xd4,0xd6,0x93,0x44,0x01,
0x32,0x82,0xc8,0xfc,0x61,0xb3,0x01,0x45,0x0c,0x2e,0x83,0x30,0xd0,0x0e,0x17,0x24,
0x0f,0x70,0x85,0x94,0xee,0x05,0x05,0x53,0x4b,0x32,0x1b,0x3f,0x98,0xd3,0x1d,0x29,
0x81,0xb0,0xae,0x1e,0x8c,0x7e,0x68,0xe0,0x60,0x5a,0x54,0x8f,0xb0,0x78,0x69,0x73,
0x06,0xa2,0x00,0x6b,0x57,0xca,0x3d,0x11,0x50,0xbd,0x04,0x30,0x4b,0x3a,0xd4,0xab,
0x5f,0x1f,0x9b,0x3d,0x13,0x74,0x27,0x88,0x3c,0x25,0xe0,0x17,0xbe,0x7a,0x79,0x45,
0x0d,0x0c,0xb0,0x8b,0xda,0x90,0xca,0x80,0x06,0x5d,0x17,0x60,0x1c,0x22,0x4c,0xd8,
0x57,0x22,0x06,0x20,0x00,0x98,0x07,0x08,0xe4,0x56,0x80,0x80,0x1c,0xc5,0xb7,0xc5,
0x82,0x0c,0x36,0xe8,0xe0,0x83,0x10,0x46,0x28,0xe1,0x84,0x14,0x56,0x68,0xa1,0x10,
0x41,0x00,0x00,0x3b,};
static const unsigned int dummy_align__404_html = 1;
static const unsigned char data__404_html[] = {
/* /404.html (10 chars) */
0x2f,0x34,0x30,0x34,0x2e,0x68,0x74,0x6d,0x6c,0x00,0x00,0x00,
/* HTTP header */
/* "HTTP/1.0 404 File not found
" (29 bytes) */
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x34,0x30,0x34,0x20,0x46,0x69,0x6c,
0x65,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x0d,0x0a,
/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip)
" (63 bytes) */
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33,
0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,
0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,
0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
/* "Content-type: text/html
" (27 bytes) */
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,
0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a,
/* raw file data (565 bytes) */
0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74,
0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69,
0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,
0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f,
0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63,
0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78,
0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20,
0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,
0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74,
0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c,
0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20,
0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,
0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20,
0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d,
0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c,
0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f,
0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69,
0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09,
0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,
0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,
0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20,
0x20,0x3c,0x68,0x32,0x3e,0x34,0x30,0x34,0x20,0x2d,0x20,0x50,0x61,0x67,0x65,0x20,
0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3c,0x2f,0x68,0x32,0x3e,0x0d,0x0a,
0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x53,0x6f,0x72,
0x72,0x79,0x2c,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,
0x20,0x61,0x72,0x65,0x20,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x69,0x6e,0x67,0x20,
0x77,0x61,0x73,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x6f,0x6e,
0x20,0x74,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,
0x65,0x72,0x2e,0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,
0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e,
0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72,
0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,
0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,
0x6d,0x6c,0x3e,0x0d,0x0a,};
static const unsigned int dummy_align__index_html = 2;
static const unsigned char data__index_html[] = {
/* /index.html (12 chars) */
0x2f,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x00,
/* HTTP header */
/* "HTTP/1.0 200 OK
" (17 bytes) */
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,
0x0a,
/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip)
" (63 bytes) */
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33,
0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,
0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,
0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
/* "Content-type: text/html
" (27 bytes) */
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,
0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a,
/* raw file data (1751 bytes) */
0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74,
0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69,
0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,
0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f,
0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63,
0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78,
0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20,
0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,
0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74,
0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c,
0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20,
0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,
0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20,
0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d,
0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c,
0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f,
0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69,
0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09,
0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,
0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,
0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20,
0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x77,
0x65,0x62,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,0x20,0x61,0x72,0x65,0x20,
0x77,0x61,0x74,0x63,0x68,0x69,0x6e,0x67,0x20,0x77,0x61,0x73,0x20,0x73,0x65,0x72,
0x76,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x73,0x69,0x6d,0x70,0x6c,0x65,0x20,
0x77,0x65,0x62,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,0x65,0x72,
0x20,0x72,0x75,0x6e,0x6e,0x69,0x6e,0x67,0x20,0x6f,0x6e,0x20,0x74,0x6f,0x70,0x20,
0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,
0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x20,0x73,0x74,0x61,0x63,0x6b,0x20,
0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x6c,
0x77,0x49,0x50,0x3c,0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,
0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,
0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,
0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,
0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,
0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,
0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,
0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,
0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,
0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,
0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,
0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,
0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,
0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,
0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,
0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,
0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,
0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,
0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,
0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,
0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,
0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,
0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,
0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,
0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,
0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,
0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,
0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,
0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,
0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,
0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,
0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,
0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,
0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,
0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,
0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x66,0x6f,0x63,0x75,0x73,0x20,0x6f,
0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x54,0x43,0x50,0x2f,0x49,
0x50,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,
0x20,0x69,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x0d,0x0a,0x09,
0x20,0x20,0x20,0x20,0x74,0x68,0x65,0x20,0x52,0x41,0x4d,0x20,0x75,0x73,0x61,0x67,
0x65,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x73,0x74,0x69,0x6c,0x6c,0x20,0x68,0x61,
0x76,0x69,0x6e,0x67,0x20,0x61,0x20,0x66,0x75,0x6c,0x6c,0x20,0x73,0x63,0x61,0x6c,
0x65,0x20,0x54,0x43,0x50,0x2e,0x20,0x54,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,
0x20,0x20,0x6d,0x61,0x6b,0x65,0x73,0x20,0x6c,0x77,0x49,0x50,0x20,0x73,0x75,0x69,
0x74,0x61,0x62,0x6c,0x65,0x20,0x66,0x6f,0x72,0x20,0x75,0x73,0x65,0x20,0x69,0x6e,
0x20,0x65,0x6d,0x62,0x65,0x64,0x64,0x65,0x64,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,
0x73,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x65,0x6e,0x73,0x0d,0x0a,0x09,0x20,0x20,
0x20,0x20,0x6f,0x66,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x20,0x6f,
0x66,0x20,0x66,0x72,0x65,0x65,0x20,0x52,0x41,0x4d,0x20,0x61,0x6e,0x64,0x20,0x72,
0x6f,0x6f,0x6d,0x20,0x66,0x6f,0x72,0x20,0x61,0x72,0x6f,0x75,0x6e,0x64,0x20,0x34,
0x30,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x0d,0x0a,0x09,0x20,0x20,
0x20,0x20,0x6f,0x66,0x20,0x63,0x6f,0x64,0x65,0x20,0x52,0x4f,0x4d,0x2e,0x0d,0x0a,
0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,
0x0a,0x09,0x20,0x20,0x20,0x20,0x4d,0x6f,0x72,0x65,0x20,0x69,0x6e,0x66,0x6f,0x72,
0x6d,0x61,0x74,0x69,0x6f,0x6e,0x20,0x61,0x62,0x6f,0x75,0x74,0x20,0x6c,0x77,0x49,
0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x61,
0x74,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,
0x20,0x68,0x6f,0x6d,0x65,0x70,0x61,0x67,0x65,0x20,0x61,0x74,0x20,0x3c,0x61,0x0d,
0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,
0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,
0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,
0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,
0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,
0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x2f,
0x3c,0x2f,0x61,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x72,0x20,0x61,0x74,
0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x77,0x69,0x6b,0x69,0x20,0x61,
0x74,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,
0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,
0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x3c,
0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,
0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e,
0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72,
0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,
0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,
0x6d,0x6c,0x3e,0x0d,0x0a,0x0d,0x0a,};
const struct fsdata_file file__img_sics_gif[] = { {
file_NULL,
data__img_sics_gif,
data__img_sics_gif + 16,
sizeof(data__img_sics_gif) - 16,
1,
}};
const struct fsdata_file file__404_html[] = { {
file__img_sics_gif,
data__404_html,
data__404_html + 12,
sizeof(data__404_html) - 12,
1,
}};
const struct fsdata_file file__index_html[] = { {
file__404_html,
data__index_html,
data__index_html + 12,
sizeof(data__index_html) - 12,
1,
}};
#define FS_ROOT file__index_html
#define FS_NUMFILES 3

File diff suppressed because it is too large Load Diff

View File

@@ -1,114 +0,0 @@
#ifndef LWIP_HTTPD_STRUCTS_H
#define LWIP_HTTPD_STRUCTS_H
#include "lwip/apps/httpd.h"
#if LWIP_HTTPD_DYNAMIC_HEADERS
/** This struct is used for a list of HTTP header strings for various
* filename extensions. */
typedef struct
{
const char *extension;
const char *content_type;
} tHTTPHeader;
/** A list of strings used in HTTP headers (see RFC 1945 HTTP/1.0 and
* RFC 2616 HTTP/1.1 for header field definitions) */
static const char * const g_psHTTPHeaderStrings[] =
{
"HTTP/1.0 200 OK\r\n",
"HTTP/1.0 404 File not found\r\n",
"HTTP/1.0 400 Bad Request\r\n",
"HTTP/1.0 501 Not Implemented\r\n",
"HTTP/1.1 200 OK\r\n",
"HTTP/1.1 404 File not found\r\n",
"HTTP/1.1 400 Bad Request\r\n",
"HTTP/1.1 501 Not Implemented\r\n",
"Content-Length: ",
"Connection: Close\r\n",
"Connection: keep-alive\r\n",
"Connection: keep-alive\r\nContent-Length: ",
"Server: "HTTPD_SERVER_AGENT"\r\n",
"\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
,"Connection: keep-alive\r\nContent-Length: 77\r\n\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
#endif
};
/* Indexes into the g_psHTTPHeaderStrings array */
#define HTTP_HDR_OK 0 /* 200 OK */
#define HTTP_HDR_NOT_FOUND 1 /* 404 File not found */
#define HTTP_HDR_BAD_REQUEST 2 /* 400 Bad request */
#define HTTP_HDR_NOT_IMPL 3 /* 501 Not Implemented */
#define HTTP_HDR_OK_11 4 /* 200 OK */
#define HTTP_HDR_NOT_FOUND_11 5 /* 404 File not found */
#define HTTP_HDR_BAD_REQUEST_11 6 /* 400 Bad request */
#define HTTP_HDR_NOT_IMPL_11 7 /* 501 Not Implemented */
#define HTTP_HDR_CONTENT_LENGTH 8 /* Content-Length: (HTTP 1.0)*/
#define HTTP_HDR_CONN_CLOSE 9 /* Connection: Close (HTTP 1.1) */
#define HTTP_HDR_CONN_KEEPALIVE 10 /* Connection: keep-alive (HTTP 1.1) */
#define HTTP_HDR_KEEPALIVE_LEN 11 /* Connection: keep-alive + Content-Length: (HTTP 1.1)*/
#define HTTP_HDR_SERVER 12 /* Server: HTTPD_SERVER_AGENT */
#define DEFAULT_404_HTML 13 /* default 404 body */
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
#define DEFAULT_404_HTML_PERSISTENT 14 /* default 404 body, but including Connection: keep-alive */
#endif
#define HTTP_HDR_HTML "Content-type: text/html\r\n\r\n"
#define HTTP_HDR_SSI "Content-type: text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n"
#define HTTP_HDR_GIF "Content-type: image/gif\r\n\r\n"
#define HTTP_HDR_PNG "Content-type: image/png\r\n\r\n"
#define HTTP_HDR_JPG "Content-type: image/jpeg\r\n\r\n"
#define HTTP_HDR_BMP "Content-type: image/bmp\r\n\r\n"
#define HTTP_HDR_ICO "Content-type: image/x-icon\r\n\r\n"
#define HTTP_HDR_APP "Content-type: application/octet-stream\r\n\r\n"
#define HTTP_HDR_JS "Content-type: application/javascript\r\n\r\n"
#define HTTP_HDR_RA "Content-type: application/javascript\r\n\r\n"
#define HTTP_HDR_CSS "Content-type: text/css\r\n\r\n"
#define HTTP_HDR_SWF "Content-type: application/x-shockwave-flash\r\n\r\n"
#define HTTP_HDR_XML "Content-type: text/xml\r\n\r\n"
#define HTTP_HDR_PDF "Content-type: application/pdf\r\n\r\n"
#define HTTP_HDR_JSON "Content-type: application/json\r\n\r\n"
#define HTTP_HDR_DEFAULT_TYPE "Content-type: text/plain\r\n\r\n"
/** A list of extension-to-HTTP header strings (see outdated RFC 1700 MEDIA TYPES
* and http://www.iana.org/assignments/media-types for registered content types
* and subtypes) */
static const tHTTPHeader g_psHTTPHeaders[] =
{
{ "html", HTTP_HDR_HTML},
{ "htm", HTTP_HDR_HTML},
{ "shtml",HTTP_HDR_SSI},
{ "shtm", HTTP_HDR_SSI},
{ "ssi", HTTP_HDR_SSI},
{ "gif", HTTP_HDR_GIF},
{ "png", HTTP_HDR_PNG},
{ "jpg", HTTP_HDR_JPG},
{ "bmp", HTTP_HDR_BMP},
{ "ico", HTTP_HDR_ICO},
{ "class",HTTP_HDR_APP},
{ "cls", HTTP_HDR_APP},
{ "js", HTTP_HDR_JS},
{ "ram", HTTP_HDR_RA},
{ "css", HTTP_HDR_CSS},
{ "swf", HTTP_HDR_SWF},
{ "xml", HTTP_HDR_XML},
{ "xsl", HTTP_HDR_XML},
{ "pdf", HTTP_HDR_PDF},
{ "json", HTTP_HDR_JSON}
};
#define NUM_HTTP_HEADERS (sizeof(g_psHTTPHeaders) / sizeof(tHTTPHeader))
#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
#if LWIP_HTTPD_SSI
static const char * const g_pcSSIExtensions[] = {
".shtml", ".shtm", ".ssi", ".xml"
};
#define NUM_SHTML_EXTENSIONS (sizeof(g_pcSSIExtensions) / sizeof(const char *))
#endif /* LWIP_HTTPD_SSI */
#endif /* LWIP_HTTPD_STRUCTS_H */

View File

@@ -1,97 +0,0 @@
#!/usr/bin/perl
open(OUTPUT, "> fsdata.c");
chdir("fs");
open(FILES, "find . -type f |");
while($file = <FILES>) {
# Do not include files in CVS directories nor backup files.
if($file =~ /(CVS|~)/) {
next;
}
chop($file);
open(HEADER, "> /tmp/header") || die $!;
if($file =~ /404/) {
print(HEADER "HTTP/1.0 404 File not found\r\n");
} else {
print(HEADER "HTTP/1.0 200 OK\r\n");
}
print(HEADER "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n");
if($file =~ /\.html$/) {
print(HEADER "Content-type: text/html\r\n");
} elsif($file =~ /\.gif$/) {
print(HEADER "Content-type: image/gif\r\n");
} elsif($file =~ /\.png$/) {
print(HEADER "Content-type: image/png\r\n");
} elsif($file =~ /\.jpg$/) {
print(HEADER "Content-type: image/jpeg\r\n");
} elsif($file =~ /\.class$/) {
print(HEADER "Content-type: application/octet-stream\r\n");
} elsif($file =~ /\.ram$/) {
print(HEADER "Content-type: audio/x-pn-realaudio\r\n");
} else {
print(HEADER "Content-type: text/plain\r\n");
}
print(HEADER "\r\n");
close(HEADER);
unless($file =~ /\.plain$/ || $file =~ /cgi/) {
system("cat /tmp/header $file > /tmp/file");
} else {
system("cp $file /tmp/file");
}
open(FILE, "/tmp/file");
unlink("/tmp/file");
unlink("/tmp/header");
$file =~ s/\.//;
$fvar = $file;
$fvar =~ s-/-_-g;
$fvar =~ s-\.-_-g;
print(OUTPUT "static const unsigned char data".$fvar."[] = {\n");
print(OUTPUT "\t/* $file */\n\t");
for($j = 0; $j < length($file); $j++) {
printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1)));
}
printf(OUTPUT "0,\n");
$i = 0;
while(read(FILE, $data, 1)) {
if($i == 0) {
print(OUTPUT "\t");
}
printf(OUTPUT "%#02x, ", unpack("C", $data));
$i++;
if($i == 10) {
print(OUTPUT "\n");
$i = 0;
}
}
print(OUTPUT "};\n\n");
close(FILE);
push(@fvars, $fvar);
push(@files, $file);
}
for($i = 0; $i < @fvars; $i++) {
$file = $files[$i];
$fvar = $fvars[$i];
if($i == 0) {
$prevfile = "NULL";
} else {
$prevfile = "file" . $fvars[$i - 1];
}
print(OUTPUT "const struct fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, ");
print(OUTPUT "data$fvar + ". (length($file) + 1) .", ");
print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n");
}
print(OUTPUT "#define FS_ROOT file$fvars[$i - 1]\n\n");
print(OUTPUT "#define FS_NUMFILES $i\n");

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +0,0 @@
This directory contains a script ('makefsdata') to create C code suitable for
httpd for given html pages (or other files) in a directory.
There is also a plain C console application doing the same and extended a bit.
Usage: htmlgen [targetdir] [-s] [-i]s
targetdir: relative or absolute path to files to convert
switch -s: toggle processing of subdirectories (default is on)
switch -e: exclude HTTP header from file (header is created at runtime, default is on)
switch -11: include HTTP 1.1 header (1.0 is default)
if targetdir not specified, makefsdata will attempt to
process files in subdirectory 'fs'.

View File

@@ -1,661 +0,0 @@
/**
* @file
* lwIP iPerf server implementation
*/
/**
* @defgroup iperf Iperf server
* @ingroup apps
*
* This is a simple performance measuring server to check your bandwith using
* iPerf2 on a PC as client.
* It is currently a minimal implementation providing an IPv4 TCP server only.
*
* @todo: implement UDP mode and IPv6
*/
/*
* Copyright (c) 2014 Simon Goldschmidt
* 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/apps/lwiperf.h"
#include "lwip/tcp.h"
#include "lwip/sys.h"
#include <string.h>
/* Currently, only TCP-over-IPv4 is implemented (does iperf support IPv6 anyway?) */
#if LWIP_IPV4 && LWIP_TCP && LWIP_CALLBACK_API
/** Specify the idle timeout (in seconds) after that the test fails */
#ifndef LWIPERF_TCP_MAX_IDLE_SEC
#define LWIPERF_TCP_MAX_IDLE_SEC 10U
#endif
#if LWIPERF_TCP_MAX_IDLE_SEC > 255
#error LWIPERF_TCP_MAX_IDLE_SEC must fit into an u8_t
#endif
/* File internal memory allocation (struct lwiperf_*): this defaults to
the heap */
#ifndef LWIPERF_ALLOC
#define LWIPERF_ALLOC(type) mem_malloc(sizeof(type))
#define LWIPERF_FREE(type, item) mem_free(item)
#endif
/** If this is 1, check that received data has the correct format */
#ifndef LWIPERF_CHECK_RX_DATA
#define LWIPERF_CHECK_RX_DATA 0
#endif
/** This is the Iperf settings struct sent from the client */
typedef struct _lwiperf_settings {
#define LWIPERF_FLAGS_ANSWER_TEST 0x80000000
#define LWIPERF_FLAGS_ANSWER_NOW 0x00000001
u32_t flags;
u32_t num_threads; /* unused for now */
u32_t remote_port;
u32_t buffer_len; /* unused for now */
u32_t win_band; /* TCP window / UDP rate: unused for now */
u32_t amount; /* pos. value: bytes?; neg. values: time (unit is 10ms: 1/100 second) */
} lwiperf_settings_t;
/** Basic connection handle */
struct _lwiperf_state_base;
typedef struct _lwiperf_state_base lwiperf_state_base_t;
struct _lwiperf_state_base {
/* 1=tcp, 0=udp */
u8_t tcp;
/* 1=server, 0=client */
u8_t server;
lwiperf_state_base_t* next;
lwiperf_state_base_t* related_server_state;
};
/** Connection handle for a TCP iperf session */
typedef struct _lwiperf_state_tcp {
lwiperf_state_base_t base;
struct tcp_pcb* server_pcb;
struct tcp_pcb* conn_pcb;
u32_t time_started;
lwiperf_report_fn report_fn;
void* report_arg;
u8_t poll_count;
u8_t next_num;
u32_t bytes_transferred;
lwiperf_settings_t settings;
u8_t have_settings_buf;
} lwiperf_state_tcp_t;
/** List of active iperf sessions */
static lwiperf_state_base_t* lwiperf_all_connections;
/** A const buffer to send from: we want to measure sending, not copying! */
static const u8_t lwiperf_txbuf_const[1600] = {
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
};
static err_t lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb);
static void lwiperf_tcp_err(void *arg, err_t err);
/** Add an iperf session to the 'active' list */
static void
lwiperf_list_add(lwiperf_state_base_t* item)
{
if (lwiperf_all_connections == NULL) {
lwiperf_all_connections = item;
} else {
item = lwiperf_all_connections;
}
}
/** Remove an iperf session from the 'active' list */
static void
lwiperf_list_remove(lwiperf_state_base_t* item)
{
lwiperf_state_base_t* prev = NULL;
lwiperf_state_base_t* iter;
for (iter = lwiperf_all_connections; iter != NULL; prev = iter, iter = iter->next) {
if (iter == item) {
if (prev == NULL) {
lwiperf_all_connections = iter->next;
} else {
prev->next = item;
}
/* @debug: ensure this item is listed only once */
for (iter = iter->next; iter != NULL; iter = iter->next) {
LWIP_ASSERT("duplicate entry", iter != item);
}
break;
}
}
}
/** Call the report function of an iperf tcp session */
static void
lwip_tcp_conn_report(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type)
{
if ((conn != NULL) && (conn->report_fn != NULL)) {
u32_t now, duration_ms, bandwidth_kbitpsec;
now = sys_now();
duration_ms = now - conn->time_started;
if (duration_ms == 0) {
bandwidth_kbitpsec = 0;
} else {
bandwidth_kbitpsec = (conn->bytes_transferred / duration_ms) * 8U;
}
conn->report_fn(conn->report_arg, report_type,
&conn->conn_pcb->local_ip, conn->conn_pcb->local_port,
&conn->conn_pcb->remote_ip, conn->conn_pcb->remote_port,
conn->bytes_transferred, duration_ms, bandwidth_kbitpsec);
}
}
/** Close an iperf tcp session */
static void
lwiperf_tcp_close(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type)
{
err_t err;
lwip_tcp_conn_report(conn, report_type);
lwiperf_list_remove(&conn->base);
if (conn->conn_pcb != NULL) {
tcp_arg(conn->conn_pcb, NULL);
tcp_poll(conn->conn_pcb, NULL, 0);
tcp_sent(conn->conn_pcb, NULL);
tcp_recv(conn->conn_pcb, NULL);
tcp_err(conn->conn_pcb, NULL);
err = tcp_close(conn->conn_pcb);
if (err != ERR_OK) {
/* don't want to wait for free memory here... */
tcp_abort(conn->conn_pcb);
}
} else {
/* no conn pcb, this is the server pcb */
err = tcp_close(conn->server_pcb);
LWIP_ASSERT("error", err != ERR_OK);
}
LWIPERF_FREE(lwiperf_state_tcp_t, conn);
}
/** Try to send more data on an iperf tcp session */
static err_t
lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn)
{
int send_more;
err_t err;
u16_t txlen;
u16_t txlen_max;
void* txptr;
u8_t apiflags;
LWIP_ASSERT("conn invalid", (conn != NULL) && conn->base.tcp && (conn->base.server == 0));
do {
send_more = 0;
if (conn->settings.amount & PP_HTONL(0x80000000)) {
/* this session is time-limited */
u32_t now = sys_now();
u32_t diff_ms = now - conn->time_started;
u32_t time = (u32_t)-(s32_t)lwip_htonl(conn->settings.amount);
u32_t time_ms = time * 10;
if (diff_ms >= time_ms) {
/* time specified by the client is over -> close the connection */
lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT);
return ERR_OK;
}
} else {
/* this session is byte-limited */
u32_t amount_bytes = lwip_htonl(conn->settings.amount);
/* @todo: this can send up to 1*MSS more than requested... */
if (amount_bytes >= conn->bytes_transferred) {
/* all requested bytes transferred -> close the connection */
lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT);
return ERR_OK;
}
}
if (conn->bytes_transferred < 24) {
/* transmit the settings a first time */
txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred];
txlen_max = (u16_t)(24 - conn->bytes_transferred);
apiflags = TCP_WRITE_FLAG_COPY;
} else if (conn->bytes_transferred < 48) {
/* transmit the settings a second time */
txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred - 24];
txlen_max = (u16_t)(48 - conn->bytes_transferred);
apiflags = TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE;
send_more = 1;
} else {
/* transmit data */
/* @todo: every x bytes, transmit the settings again */
txptr = LWIP_CONST_CAST(void*, &lwiperf_txbuf_const[conn->bytes_transferred % 10]);
txlen_max = TCP_MSS;
if (conn->bytes_transferred == 48) { /* @todo: fix this for intermediate settings, too */
txlen_max = TCP_MSS - 24;
}
apiflags = 0; /* no copying needed */
send_more = 1;
}
txlen = txlen_max;
do {
err = tcp_write(conn->conn_pcb, txptr, txlen, apiflags);
if (err == ERR_MEM) {
txlen /= 2;
}
} while ((err == ERR_MEM) && (txlen >= (TCP_MSS/2)));
if (err == ERR_OK) {
conn->bytes_transferred += txlen;
} else {
send_more = 0;
}
} while(send_more);
tcp_output(conn->conn_pcb);
return ERR_OK;
}
/** TCP sent callback, try to send more data */
static err_t
lwiperf_tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
/* @todo: check 'len' (e.g. to time ACK of all data)? for now, we just send more... */
LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
LWIP_UNUSED_ARG(tpcb);
LWIP_UNUSED_ARG(len);
conn->poll_count = 0;
return lwiperf_tcp_client_send_more(conn);
}
/** TCP connected callback (active connection), send data now */
static err_t
lwiperf_tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
LWIP_UNUSED_ARG(tpcb);
if (err != ERR_OK) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
return ERR_OK;
}
conn->poll_count = 0;
conn->time_started = sys_now();
return lwiperf_tcp_client_send_more(conn);
}
/** Start TCP connection back to the client (either parallel or after the
* receive test has finished.
*/
static err_t
lwiperf_tx_start(lwiperf_state_tcp_t* conn)
{
err_t err;
lwiperf_state_tcp_t* client_conn;
struct tcp_pcb* newpcb;
ip_addr_t remote_addr;
u16_t remote_port;
client_conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t);
if (client_conn == NULL) {
return ERR_MEM;
}
newpcb = tcp_new();
if (newpcb == NULL) {
LWIPERF_FREE(lwiperf_state_tcp_t, client_conn);
return ERR_MEM;
}
MEMCPY(client_conn, conn, sizeof(lwiperf_state_tcp_t));
client_conn->base.server = 0;
client_conn->server_pcb = NULL;
client_conn->conn_pcb = newpcb;
client_conn->time_started = sys_now(); /* @todo: set this again on 'connected' */
client_conn->poll_count = 0;
client_conn->next_num = 4; /* initial nr is '4' since the header has 24 byte */
client_conn->bytes_transferred = 0;
client_conn->settings.flags = 0; /* prevent the remote side starting back as client again */
tcp_arg(newpcb, client_conn);
tcp_sent(newpcb, lwiperf_tcp_client_sent);
tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
tcp_err(newpcb, lwiperf_tcp_err);
ip_addr_copy(remote_addr, conn->conn_pcb->remote_ip);
remote_port = (u16_t)lwip_htonl(client_conn->settings.remote_port);
err = tcp_connect(newpcb, &remote_addr, remote_port, lwiperf_tcp_client_connected);
if (err != ERR_OK) {
lwiperf_tcp_close(client_conn, LWIPERF_TCP_ABORTED_LOCAL);
return err;
}
lwiperf_list_add(&client_conn->base);
return ERR_OK;
}
/** Receive data on an iperf tcp session */
static err_t
lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
u8_t tmp;
u16_t tot_len;
u32_t packet_idx;
struct pbuf* q;
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb);
LWIP_UNUSED_ARG(tpcb);
if (err != ERR_OK) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
return ERR_OK;
}
if (p == NULL) {
/* connection closed -> test done */
if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) ==
PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
/* client requested transmission after end of test */
lwiperf_tx_start(conn);
}
lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_SERVER);
return ERR_OK;
}
tot_len = p->tot_len;
conn->poll_count = 0;
if ((!conn->have_settings_buf) || ((conn->bytes_transferred -24) % (1024*128) == 0)) {
/* wait for 24-byte header */
if (p->tot_len < sizeof(lwiperf_settings_t)) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
pbuf_free(p);
return ERR_VAL;
}
if (!conn->have_settings_buf) {
if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
pbuf_free(p);
return ERR_VAL;
}
conn->have_settings_buf = 1;
if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) ==
PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) {
/* client requested parallel transmission test */
err_t err2 = lwiperf_tx_start(conn);
if (err2 != ERR_OK) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR);
pbuf_free(p);
return err2;
}
}
} else {
if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
pbuf_free(p);
return ERR_VAL;
}
}
conn->bytes_transferred += sizeof(lwiperf_settings_t);
if (conn->bytes_transferred <= 24) {
conn->time_started = sys_now();
tcp_recved(tpcb, p->tot_len);
pbuf_free(p);
return ERR_OK;
}
conn->next_num = 4; /* 24 bytes received... */
tmp = pbuf_header(p, -24);
LWIP_ASSERT("pbuf_header failed", tmp == 0);
}
packet_idx = 0;
for (q = p; q != NULL; q = q->next) {
#if LWIPERF_CHECK_RX_DATA
const u8_t* payload = (const u8_t*)q->payload;
u16_t i;
for (i = 0; i < q->len; i++) {
u8_t val = payload[i];
u8_t num = val - '0';
if (num == conn->next_num) {
conn->next_num++;
if (conn->next_num == 10) {
conn->next_num = 0;
}
} else {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
pbuf_free(p);
return ERR_VAL;
}
}
#endif
packet_idx += q->len;
}
LWIP_ASSERT("count mismatch", packet_idx == p->tot_len);
conn->bytes_transferred += packet_idx;
tcp_recved(tpcb, tot_len);
pbuf_free(p);
return ERR_OK;
}
/** Error callback, iperf tcp session aborted */
static void
lwiperf_tcp_err(void *arg, err_t err)
{
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
LWIP_UNUSED_ARG(err);
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
}
/** TCP poll callback, try to send more data */
static err_t
lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb)
{
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb);
LWIP_UNUSED_ARG(tpcb);
if (++conn->poll_count >= LWIPERF_TCP_MAX_IDLE_SEC) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
return ERR_OK; /* lwiperf_tcp_close frees conn */
}
if (!conn->base.server) {
lwiperf_tcp_client_send_more(conn);
}
return ERR_OK;
}
/** This is called when a new client connects for an iperf tcp session */
static err_t
lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
lwiperf_state_tcp_t *s, *conn;
if ((err != ERR_OK) || (newpcb == NULL) || (arg == NULL)) {
return ERR_VAL;
}
s = (lwiperf_state_tcp_t*)arg;
conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t);
if (conn == NULL) {
return ERR_MEM;
}
memset(conn, 0, sizeof(lwiperf_state_tcp_t));
conn->base.tcp = 1;
conn->base.server = 1;
conn->base.related_server_state = &s->base;
conn->server_pcb = s->server_pcb;
conn->conn_pcb = newpcb;
conn->time_started = sys_now();
conn->report_fn = s->report_fn;
conn->report_arg = s->report_arg;
/* setup the tcp rx connection */
tcp_arg(newpcb, conn);
tcp_recv(newpcb, lwiperf_tcp_recv);
tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
tcp_err(conn->conn_pcb, lwiperf_tcp_err);
lwiperf_list_add(&conn->base);
return ERR_OK;
}
/**
* @ingroup iperf
* Start a TCP iperf server on the default TCP port (5001) and listen for
* incoming connections from iperf clients.
*
* @returns a connection handle that can be used to abort the server
* by calling @ref lwiperf_abort()
*/
void*
lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg)
{
return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT,
report_fn, report_arg);
}
/**
* @ingroup iperf
* Start a TCP iperf server on a specific IP address and port and listen for
* incoming connections from iperf clients.
*
* @returns a connection handle that can be used to abort the server
* by calling @ref lwiperf_abort()
*/
void*
lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port,
lwiperf_report_fn report_fn, void* report_arg)
{
err_t err;
struct tcp_pcb* pcb;
lwiperf_state_tcp_t* s;
if (local_addr == NULL) {
return NULL;
}
s = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t);
if (s == NULL) {
return NULL;
}
memset(s, 0, sizeof(lwiperf_state_tcp_t));
s->base.tcp = 1;
s->base.server = 1;
s->report_fn = report_fn;
s->report_arg = report_arg;
pcb = tcp_new();
if (pcb != NULL) {
err = tcp_bind(pcb, local_addr, local_port);
if (err == ERR_OK) {
s->server_pcb = tcp_listen_with_backlog(pcb, 1);
}
}
if (s->server_pcb == NULL) {
if (pcb != NULL) {
tcp_close(pcb);
}
LWIPERF_FREE(lwiperf_state_tcp_t, s);
return NULL;
}
pcb = NULL;
tcp_arg(s->server_pcb, s);
tcp_accept(s->server_pcb, lwiperf_tcp_accept);
lwiperf_list_add(&s->base);
return s;
}
/**
* @ingroup iperf
* Abort an iperf session (handle returned by lwiperf_start_tcp_server*())
*/
void
lwiperf_abort(void* lwiperf_session)
{
lwiperf_state_base_t* i, *dealloc, *last = NULL;
for (i = lwiperf_all_connections; i != NULL; ) {
if ((i == lwiperf_session) || (i->related_server_state == lwiperf_session)) {
dealloc = i;
i = i->next;
if (last != NULL) {
last->next = i;
}
LWIPERF_FREE(lwiperf_state_tcp_t, dealloc); /* @todo: type? */
} else {
last = i;
i = i->next;
}
}
}
#endif /* LWIP_IPV4 && LWIP_TCP && LWIP_CALLBACK_API */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,367 +0,0 @@
/**
* @file
* NetBIOS name service responder
*/
/**
* @defgroup netbiosns NETBIOS responder
* @ingroup apps
*
* This is an example implementation of a NetBIOS name server.
* It responds to name queries for a configurable name.
* Name resolving is not supported.
*
* Note that the device doesn't broadcast it's own name so can't
* detect duplicate names!
*/
/*
* 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.
*
*/
#include "lwip/apps/netbiosns.h"
#if LWIP_IPV4 && LWIP_UDP /* don't build if not configured for use in lwipopts.h */
#include "lwip/def.h"
#include "lwip/udp.h"
#include "lwip/netif.h"
#include <string.h>
/** default port number for "NetBIOS Name service */
#define NETBIOS_PORT 137
/** size of a NetBIOS name */
#define NETBIOS_NAME_LEN 16
/** The Time-To-Live for NetBIOS name responds (in seconds)
* Default is 300000 seconds (3 days, 11 hours, 20 minutes) */
#define NETBIOS_NAME_TTL 300000u
/** NetBIOS header flags */
#define NETB_HFLAG_RESPONSE 0x8000U
#define NETB_HFLAG_OPCODE 0x7800U
#define NETB_HFLAG_OPCODE_NAME_QUERY 0x0000U
#define NETB_HFLAG_AUTHORATIVE 0x0400U
#define NETB_HFLAG_TRUNCATED 0x0200U
#define NETB_HFLAG_RECURS_DESIRED 0x0100U
#define NETB_HFLAG_RECURS_AVAILABLE 0x0080U
#define NETB_HFLAG_BROADCAST 0x0010U
#define NETB_HFLAG_REPLYCODE 0x0008U
#define NETB_HFLAG_REPLYCODE_NOERROR 0x0000U
/** NetBIOS name flags */
#define NETB_NFLAG_UNIQUE 0x8000U
#define NETB_NFLAG_NODETYPE 0x6000U
#define NETB_NFLAG_NODETYPE_HNODE 0x6000U
#define NETB_NFLAG_NODETYPE_MNODE 0x4000U
#define NETB_NFLAG_NODETYPE_PNODE 0x2000U
#define NETB_NFLAG_NODETYPE_BNODE 0x0000U
/** NetBIOS message header */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct netbios_hdr {
PACK_STRUCT_FIELD(u16_t trans_id);
PACK_STRUCT_FIELD(u16_t flags);
PACK_STRUCT_FIELD(u16_t questions);
PACK_STRUCT_FIELD(u16_t answerRRs);
PACK_STRUCT_FIELD(u16_t authorityRRs);
PACK_STRUCT_FIELD(u16_t additionalRRs);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** NetBIOS message name part */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct netbios_name_hdr {
PACK_STRUCT_FLD_8(u8_t nametype);
PACK_STRUCT_FLD_8(u8_t encname[(NETBIOS_NAME_LEN*2)+1]);
PACK_STRUCT_FIELD(u16_t type);
PACK_STRUCT_FIELD(u16_t cls);
PACK_STRUCT_FIELD(u32_t ttl);
PACK_STRUCT_FIELD(u16_t datalen);
PACK_STRUCT_FIELD(u16_t flags);
PACK_STRUCT_FLD_S(ip4_addr_p_t addr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** NetBIOS message */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct netbios_resp
{
struct netbios_hdr resp_hdr;
struct netbios_name_hdr resp_name;
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef NETBIOS_LWIP_NAME
#define NETBIOS_LOCAL_NAME NETBIOS_LWIP_NAME
#else
static char netbiosns_local_name[NETBIOS_NAME_LEN];
#define NETBIOS_LOCAL_NAME netbiosns_local_name
#endif
struct udp_pcb *netbiosns_pcb;
/** Decode a NetBIOS name (from packet to string) */
static int
netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len)
{
char *pname;
char cname;
char cnbname;
int idx = 0;
LWIP_UNUSED_ARG(name_dec_len);
/* Start decoding netbios name. */
pname = name_enc;
for (;;) {
/* Every two characters of the first level-encoded name
* turn into one character in the decoded name. */
cname = *pname;
if (cname == '\0')
break; /* no more characters */
if (cname == '.')
break; /* scope ID follows */
if (cname < 'A' || cname > 'Z') {
/* Not legal. */
return -1;
}
cname -= 'A';
cnbname = cname << 4;
pname++;
cname = *pname;
if (cname == '\0' || cname == '.') {
/* No more characters in the name - but we're in
* the middle of a pair. Not legal. */
return -1;
}
if (cname < 'A' || cname > 'Z') {
/* Not legal. */
return -1;
}
cname -= 'A';
cnbname |= cname;
pname++;
/* Do we have room to store the character? */
if (idx < NETBIOS_NAME_LEN) {
/* Yes - store the character. */
name_dec[idx++] = (cnbname!=' '?cnbname:'\0');
}
}
return 0;
}
#if 0 /* function currently unused */
/** Encode a NetBIOS name (from string to packet) - currently unused because
we don't ask for names. */
static int
netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len)
{
char *pname;
char cname;
unsigned char ucname;
int idx = 0;
/* Start encoding netbios name. */
pname = name_enc;
for (;;) {
/* Every two characters of the first level-encoded name
* turn into one character in the decoded name. */
cname = *pname;
if (cname == '\0')
break; /* no more characters */
if (cname == '.')
break; /* scope ID follows */
if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) {
/* Not legal. */
return -1;
}
/* Do we have room to store the character? */
if (idx >= name_dec_len) {
return -1;
}
/* Yes - store the character. */
ucname = cname;
name_dec[idx++] = ('A'+((ucname>>4) & 0x0F));
name_dec[idx++] = ('A'+( ucname & 0x0F));
pname++;
}
/* Fill with "space" coding */
for (;idx < name_dec_len - 1;) {
name_dec[idx++] = 'C';
name_dec[idx++] = 'A';
}
/* Terminate string */
name_dec[idx] = '\0';
return 0;
}
#endif /* 0 */
/** NetBIOS Name service recv callback */
static void
netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
LWIP_UNUSED_ARG(arg);
/* if packet is valid */
if (p != NULL) {
char netbios_name[NETBIOS_NAME_LEN+1];
struct netbios_hdr* netbios_hdr = (struct netbios_hdr*)p->payload;
struct netbios_name_hdr* netbios_name_hdr = (struct netbios_name_hdr*)(netbios_hdr+1);
/* we only answer if we got a default interface */
if (netif_default != NULL) {
/* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */
/* if the packet is a NetBIOS name query question */
if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) &&
((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) &&
(netbios_hdr->questions == PP_NTOHS(1))) {
/* decode the NetBIOS name */
netbiosns_name_decode((char*)(netbios_name_hdr->encname), netbios_name, sizeof(netbios_name));
/* if the packet is for us */
if (lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) == 0) {
struct pbuf *q;
struct netbios_resp *resp;
q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM);
if (q != NULL) {
resp = (struct netbios_resp*)q->payload;
/* prepare NetBIOS header response */
resp->resp_hdr.trans_id = netbios_hdr->trans_id;
resp->resp_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE |
NETB_HFLAG_OPCODE_NAME_QUERY |
NETB_HFLAG_AUTHORATIVE |
NETB_HFLAG_RECURS_DESIRED);
resp->resp_hdr.questions = 0;
resp->resp_hdr.answerRRs = PP_HTONS(1);
resp->resp_hdr.authorityRRs = 0;
resp->resp_hdr.additionalRRs = 0;
/* prepare NetBIOS header datas */
MEMCPY( resp->resp_name.encname, netbios_name_hdr->encname, sizeof(netbios_name_hdr->encname));
resp->resp_name.nametype = netbios_name_hdr->nametype;
resp->resp_name.type = netbios_name_hdr->type;
resp->resp_name.cls = netbios_name_hdr->cls;
resp->resp_name.ttl = PP_HTONL(NETBIOS_NAME_TTL);
resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags)+sizeof(resp->resp_name.addr));
resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE);
ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default));
/* send the NetBIOS response */
udp_sendto(upcb, q, addr, port);
/* free the "reference" pbuf */
pbuf_free(q);
}
}
}
}
/* free the pbuf */
pbuf_free(p);
}
}
/**
* @ingroup netbiosns
* Init netbios responder
*/
void
netbiosns_init(void)
{
#ifdef NETBIOS_LWIP_NAME
LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN);
#endif
netbiosns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
if (netbiosns_pcb != NULL) {
/* we have to be allowed to send broadcast packets! */
ip_set_option(netbiosns_pcb, SOF_BROADCAST);
udp_bind(netbiosns_pcb, IP_ANY_TYPE, NETBIOS_PORT);
udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb);
}
}
#ifndef NETBIOS_LWIP_NAME
/**
* @ingroup netbiosns
* Set netbios name. ATTENTION: the hostname must be less than 15 characters!
*/
void
netbiosns_set_name(const char* hostname)
{
size_t copy_len = strlen(hostname);
LWIP_ASSERT("NetBIOS name is too long!", copy_len < NETBIOS_NAME_LEN);
if (copy_len >= NETBIOS_NAME_LEN) {
copy_len = NETBIOS_NAME_LEN - 1;
}
MEMCPY(netbiosns_local_name, hostname, copy_len + 1);
}
#endif
/**
* @ingroup netbiosns
* Stop netbios responder
*/
void
netbiosns_stop(void)
{
if (netbiosns_pcb != NULL) {
udp_remove(netbiosns_pcb);
netbiosns_pcb = NULL;
}
}
#endif /* LWIP_IPV4 && LWIP_UDP */

View File

@@ -1,749 +0,0 @@
/**
* @file
* Abstract Syntax Notation One (ISO 8824, 8825) encoding
*
* @todo not optimised (yet), favor correctness over speed, favor speed over size
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
* Martin Hentschel <info@cl-soft.de>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "snmp_asn1.h"
#define PBUF_OP_EXEC(code) \
if ((code) != ERR_OK) { \
return ERR_BUF; \
}
/**
* Encodes a TLV into a pbuf stream.
*
* @param pbuf_stream points to a pbuf stream
* @param tlv TLV to encode
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
{
u8_t data;
u8_t length_bytes_required;
/* write type */
if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
/* extended format is not used by SNMP so we do not accept those values */
return ERR_ARG;
}
if (tlv->type_len != 0) {
/* any other value as auto is not accepted for type (we always use one byte because extended syntax is prohibited) */
return ERR_ARG;
}
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, tlv->type));
tlv->type_len = 1;
/* write length */
if (tlv->value_len <= 127) {
length_bytes_required = 1;
} else if (tlv->value_len <= 255) {
length_bytes_required = 2;
} else {
length_bytes_required = 3;
}
/* check for forced min length */
if (tlv->length_len > 0) {
if (tlv->length_len < length_bytes_required) {
/* unable to code requested length in requested number of bytes */
return ERR_ARG;
}
length_bytes_required = tlv->length_len;
} else {
tlv->length_len = length_bytes_required;
}
if (length_bytes_required > 1) {
/* multi byte representation required */
length_bytes_required--;
data = 0x80 | length_bytes_required; /* extended length definition, 1 length byte follows */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
while (length_bytes_required > 1) {
if (length_bytes_required == 2) {
/* append high byte */
data = (u8_t)(tlv->value_len >> 8);
} else {
/* append leading 0x00 */
data = 0x00;
}
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
length_bytes_required--;
}
}
/* append low byte */
data = (u8_t)(tlv->value_len & 0xFF);
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
return ERR_OK;
}
/**
* Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
*
* @param pbuf_stream points to a pbuf stream
* @param raw_len raw data length
* @param raw points raw data
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len)
{
PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len));
return ERR_OK;
}
/**
* Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
*
* @param pbuf_stream points to a pbuf stream
* @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
* @param value is the host order u32_t value to be encoded
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_u32t_cnt()
*/
err_t
snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value)
{
if (octets_needed > 5) {
return ERR_ARG;
}
if (octets_needed == 5) {
/* not enough bits in 'value' add leading 0x00 */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
octets_needed--;
}
while (octets_needed > 1) {
octets_needed--;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
}
/* (only) one least significant octet */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
return ERR_OK;
}
/**
* Encodes u64_t (counter64) into a pbuf chained ASN1 msg.
*
* @param pbuf_stream points to a pbuf stream
* @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
* @param value is the host order u32_t value to be encoded
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_u64t_cnt()
*/
err_t
snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value)
{
if (octets_needed > 9) {
return ERR_ARG;
}
if (octets_needed == 9) {
/* not enough bits in 'value' add leading 0x00 */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
octets_needed--;
}
while (octets_needed > 4) {
octets_needed--;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> ((octets_needed-4) << 3))));
}
/* skip to low u32 */
value++;
while (octets_needed > 1) {
octets_needed--;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> (octets_needed << 3))));
}
/* always write at least one octet (also in case of value == 0) */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value)));
return ERR_OK;
}
/**
* Encodes s32_t integer into a pbuf chained ASN1 msg.
*
* @param pbuf_stream points to a pbuf stream
* @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
* @param value is the host order s32_t value to be encoded
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_s32t_cnt()
*/
err_t
snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value)
{
while (octets_needed > 1) {
octets_needed--;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
}
/* (only) one least significant octet */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
return ERR_OK;
}
/**
* Encodes object identifier into a pbuf chained ASN1 msg.
*
* @param pbuf_stream points to a pbuf stream
* @param oid points to object identifier array
* @param oid_len object identifier array length
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len)
{
if (oid_len > 1) {
/* write compressed first two sub id's */
u32_t compressed_byte = ((oid[0] * 40) + oid[1]);
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)compressed_byte));
oid_len -= 2;
oid += 2;
} else {
/* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
/* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
return ERR_ARG;
}
while (oid_len > 0) {
u32_t sub_id;
u8_t shift, tail;
oid_len--;
sub_id = *oid;
tail = 0;
shift = 28;
while (shift > 0) {
u8_t code;
code = (u8_t)(sub_id >> shift);
if ((code != 0) || (tail != 0)) {
tail = 1;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, code | 0x80));
}
shift -= 7;
}
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)sub_id & 0x7F));
/* proceed to next sub-identifier */
oid++;
}
return ERR_OK;
}
/**
* Returns octet count for length.
*
* @param length parameter length
* @param octets_needed points to the return value
*/
void
snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
{
if (length < 0x80U) {
*octets_needed = 1;
} else if (length < 0x100U) {
*octets_needed = 2;
} else {
*octets_needed = 3;
}
}
/**
* Returns octet count for an u32_t.
*
* @param value value to be encoded
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
void
snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
{
if (value < 0x80UL) {
*octets_needed = 1;
} else if (value < 0x8000UL) {
*octets_needed = 2;
} else if (value < 0x800000UL) {
*octets_needed = 3;
} else if (value < 0x80000000UL) {
*octets_needed = 4;
} else {
*octets_needed = 5;
}
}
/**
* Returns octet count for an u64_t.
*
* @param value value to be encoded
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
void
snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed)
{
/* check if high u32 is 0 */
if (*value == 0x00) {
/* only low u32 is important */
value++;
snmp_asn1_enc_u32t_cnt(*value, octets_needed);
} else {
/* low u32 does not matter for length determination */
snmp_asn1_enc_u32t_cnt(*value, octets_needed);
*octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */
}
}
/**
* Returns octet count for an s32_t.
*
* @param value value to be encoded
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed.
*/
void
snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
{
if (value < 0) {
value = ~value;
}
if (value < 0x80L) {
*octets_needed = 1;
} else if (value < 0x8000L) {
*octets_needed = 2;
} else if (value < 0x800000L) {
*octets_needed = 3;
} else {
*octets_needed = 4;
}
}
/**
* Returns octet count for an object identifier.
*
* @param oid points to object identifier array
* @param oid_len object identifier array length
* @param octets_needed points to the return value
*/
void
snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed)
{
u32_t sub_id;
*octets_needed = 0;
if (oid_len > 1) {
/* compressed prefix in one octet */
(*octets_needed)++;
oid_len -= 2;
oid += 2;
}
while (oid_len > 0) {
oid_len--;
sub_id = *oid;
sub_id >>= 7;
(*octets_needed)++;
while (sub_id > 0) {
sub_id >>= 7;
(*octets_needed)++;
}
oid++;
}
}
/**
* Decodes a TLV from a pbuf stream.
*
* @param pbuf_stream points to a pbuf stream
* @param tlv returns decoded TLV
* @return ERR_OK if successful, ERR_VAL if we can't decode
*/
err_t
snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
{
u8_t data;
/* decode type first */
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
tlv->type = data;
if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
/* extended format is not used by SNMP so we do not accept those values */
return ERR_VAL;
}
tlv->type_len = 1;
/* now, decode length */
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
if (data < 0x80) { /* short form */
tlv->length_len = 1;
tlv->value_len = data;
} else if (data > 0x80) { /* long form */
u8_t length_bytes = data - 0x80;
tlv->length_len = length_bytes + 1; /* this byte + defined number of length bytes following */
tlv->value_len = 0;
while (length_bytes > 0) {
/* we only support up to u16.maxvalue-1 (2 bytes) but have to accept leading zero bytes */
if (tlv->value_len > 0xFF) {
return ERR_VAL;
}
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
tlv->value_len <<= 8;
tlv->value_len |= data;
/* take care for special value used for indefinite length */
if (tlv->value_len == 0xFFFF) {
return ERR_VAL;
}
length_bytes--;
}
} else { /* data == 0x80 indefinite length form */
/* (not allowed for SNMP; RFC 1157, 3.2.2) */
return ERR_VAL;
}
return ERR_OK;
}
/**
* Decodes positive integer (counter, gauge, timeticks) into u32_t.
*
* @param pbuf_stream points to a pbuf stream
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
err_t
snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
{
u8_t data;
if ((len > 0) && (len <= 5)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
/* expecting sign bit to be zero, only unsigned please! */
if (((len == 5) && (data == 0x00)) || ((len < 5) && ((data & 0x80) == 0))) {
*value = data;
len--;
while (len > 0) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
*value <<= 8;
*value |= data;
}
return ERR_OK;
}
}
return ERR_VAL;
}
/**
* Decodes large positive integer (counter64) into 2x u32_t.
*
* @param pbuf_stream points to a pbuf stream
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
err_t
snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
{
u8_t data;
if (len <= 4) {
/* high u32 is 0 */
*value = 0;
/* directly skip to low u32 */
value++;
}
if ((len > 0) && (len <= 9)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
/* expecting sign bit to be zero, only unsigned please! */
if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) {
*value = data;
len--;
while (len > 0) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
if (len == 4) {
/* skip to low u32 */
value++;
*value = 0;
} else {
*value <<= 8;
}
*value |= data;
len--;
}
return ERR_OK;
}
}
return ERR_VAL;
}
/**
* Decodes integer into s32_t.
*
* @param pbuf_stream points to a pbuf stream
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed!
*/
err_t
snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value)
{
#if BYTE_ORDER == LITTLE_ENDIAN
u8_t *lsb_ptr = (u8_t*)value;
#endif
#if BYTE_ORDER == BIG_ENDIAN
u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
#endif
u8_t sign;
u8_t data;
if ((len > 0) && (len < 5)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
if (data & 0x80) {
/* negative, start from -1 */
*value = -1;
sign = 1;
*lsb_ptr &= data;
} else {
/* positive, start from 0 */
*value = 0;
sign = 0;
*lsb_ptr |= data;
}
/* OR/AND octets with value */
while (len > 0) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
#if BYTE_ORDER == LITTLE_ENDIAN
*value <<= 8;
#endif
#if BYTE_ORDER == BIG_ENDIAN
*value >>= 8;
#endif
if (sign) {
*lsb_ptr |= 255;
*lsb_ptr &= data;
} else {
*lsb_ptr |= data;
}
}
return ERR_OK;
}
return ERR_VAL;
}
/**
* Decodes object identifier from incoming message into array of u32_t.
*
* @param pbuf_stream points to a pbuf stream
* @param len length of the coded object identifier
* @param oid return decoded object identifier
* @param oid_len return decoded object identifier length
* @param oid_max_len size of oid buffer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len)
{
u32_t *oid_ptr;
u8_t data;
*oid_len = 0;
oid_ptr = oid;
if (len > 0) {
if (oid_max_len < 2) {
return ERR_MEM;
}
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
/* first compressed octet */
if (data == 0x2B) {
/* (most) common case 1.3 (iso.org) */
*oid_ptr = 1;
oid_ptr++;
*oid_ptr = 3;
oid_ptr++;
} else if (data < 40) {
*oid_ptr = 0;
oid_ptr++;
*oid_ptr = data;
oid_ptr++;
} else if (data < 80) {
*oid_ptr = 1;
oid_ptr++;
*oid_ptr = data - 40;
oid_ptr++;
} else {
*oid_ptr = 2;
oid_ptr++;
*oid_ptr = data - 80;
oid_ptr++;
}
*oid_len = 2;
} else {
/* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */
return ERR_OK;
}
while ((len > 0) && (*oid_len < oid_max_len)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
if ((data & 0x80) == 0x00) {
/* sub-identifier uses single octet */
*oid_ptr = data;
} else {
/* sub-identifier uses multiple octets */
u32_t sub_id = (data & ~0x80);
while ((len > 0) && ((data & 0x80) != 0)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
sub_id = (sub_id << 7) + (data & ~0x80);
}
if ((data & 0x80) != 0) {
/* "more bytes following" bit still set at end of len */
return ERR_VAL;
}
*oid_ptr = sub_id;
}
oid_ptr++;
(*oid_len)++;
}
if (len > 0) {
/* OID to long to fit in our buffer */
return ERR_MEM;
}
return ERR_OK;
}
/**
* Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
* from incoming message into array.
*
* @param pbuf_stream points to a pbuf stream
* @param len length of the coded raw data (zero is valid, e.g. empty string!)
* @param buf return raw bytes
* @param buf_len returns length of the raw return value
* @param buf_max_len buffer size
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len)
{
if (len > buf_max_len) {
/* not enough dst space */
return ERR_MEM;
}
*buf_len = len;
while (len > 0) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf));
buf++;
len--;
}
return ERR_OK;
}
#endif /* LWIP_SNMP */

View File

@@ -1,108 +0,0 @@
/**
* @file
* Abstract Syntax Notation One (ISO 8824, 8825) codec.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* Copyright (c) 2016 Elias Oenal.
* 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.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
* Martin Hentschel <info@cl-soft.de>
* Elias Oenal <lwip@eliasoenal.com>
*/
#ifndef LWIP_HDR_APPS_SNMP_ASN1_H
#define LWIP_HDR_APPS_SNMP_ASN1_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP
#include "lwip/err.h"
#include "lwip/apps/snmp_core.h"
#include "snmp_pbuf_stream.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SNMP_ASN1_TLV_INDEFINITE_LENGTH 0x80
#define SNMP_ASN1_CLASS_MASK 0xC0
#define SNMP_ASN1_CONTENTTYPE_MASK 0x20
#define SNMP_ASN1_DATATYPE_MASK 0x1F
#define SNMP_ASN1_DATATYPE_EXTENDED 0x1F /* DataType indicating that datatype is encoded in following bytes */
/* context specific (SNMP) tags (from SNMP spec. RFC1157) */
#define SNMP_ASN1_CONTEXT_PDU_GET_REQ 0
#define SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ 1
#define SNMP_ASN1_CONTEXT_PDU_GET_RESP 2
#define SNMP_ASN1_CONTEXT_PDU_SET_REQ 3
#define SNMP_ASN1_CONTEXT_PDU_TRAP 4
#define SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ 5
#define SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_OBJECT 0
#define SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW 2
struct snmp_asn1_tlv
{
u8_t type; /* only U8 because extended types are not specified by SNMP */
u8_t type_len; /* encoded length of 'type' field (normally 1) */
u8_t length_len; /* indicates how many bytes are required to encode the 'value_len' field */
u16_t value_len; /* encoded length of the value */
};
#define SNMP_ASN1_TLV_HDR_LENGTH(tlv) ((tlv).type_len + (tlv).length_len)
#define SNMP_ASN1_TLV_LENGTH(tlv) ((tlv).type_len + (tlv).length_len + (tlv).value_len)
#define SNMP_ASN1_SET_TLV_PARAMS(tlv, type_, length_len_, value_len_) do { (tlv).type = (type_); (tlv).type_len = 0; (tlv).length_len = (length_len_); (tlv).value_len = (value_len_); } while (0);
err_t snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv);
err_t snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value);
err_t snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value);
err_t snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value);
err_t snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len);
err_t snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len);
err_t snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv);
void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);
void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);
void snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed);
void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);
void snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed);
err_t snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len);
err_t snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value);
err_t snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value);
err_t snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value);
err_t snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_ASN1_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,76 +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: Martin Hentschel <info@cl-soft.de>
*
*/
#ifndef LWIP_HDR_APPS_SNMP_CORE_PRIV_H
#define LWIP_HDR_APPS_SNMP_CORE_PRIV_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_core.h"
#include "snmp_asn1.h"
#ifdef __cplusplus
extern "C" {
#endif
/* (outdated) SNMPv1 error codes
* shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request
*/
#define SNMP_ERR_NOSUCHNAME 2
#define SNMP_ERR_BADVALUE 3
#define SNMP_ERR_READONLY 4
/* error codes which are internal and shall not be used by MIBS
* shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request
*/
#define SNMP_ERR_TOOBIG 1
#define SNMP_ERR_AUTHORIZATIONERROR 16
#define SNMP_ERR_NOSUCHOBJECT SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_OBJECT
#define SNMP_ERR_ENDOFMIBVIEW SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW
const struct snmp_node* snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t* oid_instance_len);
const struct snmp_node* snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id* oidret);
typedef u8_t (*snmp_validate_node_instance_method)(struct snmp_node_instance*, void*);
u8_t snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance* node_instance);
u8_t snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_validate_node_instance_method validate_node_instance_method, void* validate_node_instance_arg, struct snmp_obj_id* node_oid, struct snmp_node_instance* node_instance);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_CORE_PRIV_H */

View File

@@ -1,116 +0,0 @@
/**
* @file
* Management Information Base II (RFC1213) objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
/**
* @defgroup snmp_mib2 MIB2
* @ingroup snmp
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP && SNMP_LWIP_MIB2 /* don't build if not configured for use in lwipopts.h */
#if !LWIP_STATS
#error LWIP_SNMP MIB2 needs LWIP_STATS (for MIB2)
#endif
#if !MIB2_STATS
#error LWIP_SNMP MIB2 needs MIB2_STATS (for MIB2)
#endif
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_scalar.h"
#if SNMP_USE_NETCONN
#include "lwip/tcpip.h"
#include "lwip/priv/tcpip_priv.h"
void
snmp_mib2_lwip_synchronizer(snmp_threadsync_called_fn fn, void* arg)
{
#if LWIP_TCPIP_CORE_LOCKING
LOCK_TCPIP_CORE();
fn(arg);
UNLOCK_TCPIP_CORE();
#else
tcpip_callback(fn, arg);
#endif
}
struct snmp_threadsync_instance snmp_mib2_lwip_locks;
#endif
/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */
/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */
/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */
/* --- mib-2 .1.3.6.1.2.1 ----------------------------------------------------- */
extern const struct snmp_scalar_array_node snmp_mib2_snmp_root;
extern const struct snmp_tree_node snmp_mib2_udp_root;
extern const struct snmp_tree_node snmp_mib2_tcp_root;
extern const struct snmp_scalar_array_node snmp_mib2_icmp_root;
extern const struct snmp_tree_node snmp_mib2_interface_root;
extern const struct snmp_scalar_array_node snmp_mib2_system_node;
extern const struct snmp_tree_node snmp_mib2_at_root;
extern const struct snmp_tree_node snmp_mib2_ip_root;
static const struct snmp_node* const mib2_nodes[] = {
&snmp_mib2_system_node.node.node,
&snmp_mib2_interface_root.node,
#if LWIP_ARP && LWIP_IPV4
&snmp_mib2_at_root.node,
#endif /* LWIP_ARP && LWIP_IPV4 */
#if LWIP_IPV4
&snmp_mib2_ip_root.node,
#endif /* LWIP_IPV4 */
#if LWIP_ICMP
&snmp_mib2_icmp_root.node.node,
#endif /* LWIP_ICMP */
#if LWIP_TCP
&snmp_mib2_tcp_root.node,
#endif /* LWIP_TCP */
#if LWIP_UDP
&snmp_mib2_udp_root.node,
#endif /* LWIP_UDP */
&snmp_mib2_snmp_root.node.node
};
static const struct snmp_tree_node mib2_root = SNMP_CREATE_TREE_NODE(1, mib2_nodes);
static const u32_t mib2_base_oid_arr[] = { 1,3,6,1,2,1 };
const struct snmp_mib mib2 = SNMP_MIB_CREATE(mib2_base_oid_arr, &mib2_root.node);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */

View File

@@ -1,182 +0,0 @@
/**
* @file
* Management Information Base II (RFC1213) ICMP objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/icmp.h"
#include "lwip/stats.h"
#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_ICMP
#if SNMP_USE_NETCONN
#define SYNC_NODE_NAME(node_name) node_name ## _synced
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
#else
#define SYNC_NODE_NAME(node_name) node_name
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
#endif
/* --- icmp .1.3.6.1.2.1.5 ----------------------------------------------------- */
static s16_t
icmp_get_value(const struct snmp_scalar_array_node_def *node, void *value)
{
u32_t *uint_ptr = (u32_t*)value;
switch (node->oid) {
case 1: /* icmpInMsgs */
*uint_ptr = STATS_GET(mib2.icmpinmsgs);
return sizeof(*uint_ptr);
case 2: /* icmpInErrors */
*uint_ptr = STATS_GET(mib2.icmpinerrors);
return sizeof(*uint_ptr);
case 3: /* icmpInDestUnreachs */
*uint_ptr = STATS_GET(mib2.icmpindestunreachs);
return sizeof(*uint_ptr);
case 4: /* icmpInTimeExcds */
*uint_ptr = STATS_GET(mib2.icmpintimeexcds);
return sizeof(*uint_ptr);
case 5: /* icmpInParmProbs */
*uint_ptr = STATS_GET(mib2.icmpinparmprobs);
return sizeof(*uint_ptr);
case 6: /* icmpInSrcQuenchs */
*uint_ptr = STATS_GET(mib2.icmpinsrcquenchs);
return sizeof(*uint_ptr);
case 7: /* icmpInRedirects */
*uint_ptr = STATS_GET(mib2.icmpinredirects);
return sizeof(*uint_ptr);
case 8: /* icmpInEchos */
*uint_ptr = STATS_GET(mib2.icmpinechos);
return sizeof(*uint_ptr);
case 9: /* icmpInEchoReps */
*uint_ptr = STATS_GET(mib2.icmpinechoreps);
return sizeof(*uint_ptr);
case 10: /* icmpInTimestamps */
*uint_ptr = STATS_GET(mib2.icmpintimestamps);
return sizeof(*uint_ptr);
case 11: /* icmpInTimestampReps */
*uint_ptr = STATS_GET(mib2.icmpintimestampreps);
return sizeof(*uint_ptr);
case 12: /* icmpInAddrMasks */
*uint_ptr = STATS_GET(mib2.icmpinaddrmasks);
return sizeof(*uint_ptr);
case 13: /* icmpInAddrMaskReps */
*uint_ptr = STATS_GET(mib2.icmpinaddrmaskreps);
return sizeof(*uint_ptr);
case 14: /* icmpOutMsgs */
*uint_ptr = STATS_GET(mib2.icmpoutmsgs);
return sizeof(*uint_ptr);
case 15: /* icmpOutErrors */
*uint_ptr = STATS_GET(mib2.icmpouterrors);
return sizeof(*uint_ptr);
case 16: /* icmpOutDestUnreachs */
*uint_ptr = STATS_GET(mib2.icmpoutdestunreachs);
return sizeof(*uint_ptr);
case 17: /* icmpOutTimeExcds */
*uint_ptr = STATS_GET(mib2.icmpouttimeexcds);
return sizeof(*uint_ptr);
case 18: /* icmpOutParmProbs: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
case 19: /* icmpOutSrcQuenchs: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
case 20: /* icmpOutRedirects: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
case 21: /* icmpOutEchos */
*uint_ptr = STATS_GET(mib2.icmpoutechos);
return sizeof(*uint_ptr);
case 22: /* icmpOutEchoReps */
*uint_ptr = STATS_GET(mib2.icmpoutechoreps);
return sizeof(*uint_ptr);
case 23: /* icmpOutTimestamps: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
case 24: /* icmpOutTimestampReps: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
case 25: /* icmpOutAddrMasks: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
case 26: /* icmpOutAddrMaskReps: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_value(): unknown id: %"S32_F"\n", node->oid));
break;
}
return 0;
}
static const struct snmp_scalar_array_node_def icmp_nodes[] = {
{ 1, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 2, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 3, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 4, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 5, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 6, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 7, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 8, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 9, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{21, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{22, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{23, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{24, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{25, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{26, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}
};
const struct snmp_scalar_array_node snmp_mib2_icmp_root = SNMP_SCALAR_CREATE_ARRAY_NODE(5, icmp_nodes, icmp_get_value, NULL, NULL);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_ICMP */

View File

@@ -1,375 +0,0 @@
/**
* @file
* Management Information Base II (RFC1213) INTERFACES objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/netif.h"
#include "lwip/stats.h"
#include <string.h>
#if LWIP_SNMP && SNMP_LWIP_MIB2
#if SNMP_USE_NETCONN
#define SYNC_NODE_NAME(node_name) node_name ## _synced
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
#else
#define SYNC_NODE_NAME(node_name) node_name
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
#endif
/* --- interfaces .1.3.6.1.2.1.2 ----------------------------------------------------- */
static s16_t
interfaces_get_value(struct snmp_node_instance* instance, void* value)
{
if (instance->node->oid == 1) {
s32_t *sint_ptr = (s32_t*)value;
s32_t num_netifs = 0;
struct netif *netif = netif_list;
while (netif != NULL) {
num_netifs++;
netif = netif->next;
}
*sint_ptr = num_netifs;
return sizeof(*sint_ptr);
}
return 0;
}
/* list of allowed value ranges for incoming OID */
static const struct snmp_oid_range interfaces_Table_oid_ranges[] = {
{ 1, 0xff } /* netif->num is u8_t */
};
static const u8_t iftable_ifOutQLen = 0;
static const u8_t iftable_ifOperStatus_up = 1;
static const u8_t iftable_ifOperStatus_down = 2;
static const u8_t iftable_ifAdminStatus_up = 1;
static const u8_t iftable_ifAdminStatus_lowerLayerDown = 7;
static const u8_t iftable_ifAdminStatus_down = 2;
static snmp_err_t
interfaces_Table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance)
{
u32_t ifIndex;
struct netif *netif;
LWIP_UNUSED_ARG(column);
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, interfaces_Table_oid_ranges, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges))) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* get netif index from incoming OID */
ifIndex = row_oid[0];
/* find netif with index */
netif = netif_list;
while (netif != NULL) {
if (netif_to_num(netif) == ifIndex) {
/* store netif pointer for subsequent operations (get/test/set) */
cell_instance->reference.ptr = netif;
return SNMP_ERR_NOERROR;
}
netif = netif->next;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
interfaces_Table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance)
{
struct netif *netif;
struct snmp_next_oid_state state;
u32_t result_temp[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)];
LWIP_UNUSED_ARG(column);
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges));
/* iterate over all possible OIDs to find the next one */
netif = netif_list;
while (netif != NULL) {
u32_t test_oid[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)];
test_oid[0] = netif_to_num(netif);
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges), netif);
netif = netif->next;
}
/* did we find a next one? */
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
/* store netif pointer for subsequent operations (get/test/set) */
cell_instance->reference.ptr = /* (struct netif*) */state.reference;
return SNMP_ERR_NOERROR;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static s16_t
interfaces_Table_get_value(struct snmp_node_instance* instance, void* value)
{
struct netif *netif = (struct netif*)instance->reference.ptr;
u32_t* value_u32 = (u32_t*)value;
s32_t* value_s32 = (s32_t*)value;
u16_t value_len;
switch (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id))
{
case 1: /* ifIndex */
*value_s32 = netif_to_num(netif);
value_len = sizeof(*value_s32);
break;
case 2: /* ifDescr */
value_len = sizeof(netif->name);
MEMCPY(value, netif->name, value_len);
break;
case 3: /* ifType */
*value_s32 = netif->link_type;
value_len = sizeof(*value_s32);
break;
case 4: /* ifMtu */
*value_s32 = netif->mtu;
value_len = sizeof(*value_s32);
break;
case 5: /* ifSpeed */
*value_u32 = netif->link_speed;
value_len = sizeof(*value_u32);
break;
case 6: /* ifPhysAddress */
value_len = sizeof(netif->hwaddr);
MEMCPY(value, &netif->hwaddr, value_len);
break;
case 7: /* ifAdminStatus */
if (netif_is_up(netif)) {
*value_s32 = iftable_ifOperStatus_up;
} else {
*value_s32 = iftable_ifOperStatus_down;
}
value_len = sizeof(*value_s32);
break;
case 8: /* ifOperStatus */
if (netif_is_up(netif)) {
if (netif_is_link_up(netif)) {
*value_s32 = iftable_ifAdminStatus_up;
} else {
*value_s32 = iftable_ifAdminStatus_lowerLayerDown;
}
} else {
*value_s32 = iftable_ifAdminStatus_down;
}
value_len = sizeof(*value_s32);
break;
case 9: /* ifLastChange */
*value_u32 = netif->ts;
value_len = sizeof(*value_u32);
break;
case 10: /* ifInOctets */
*value_u32 = netif->mib2_counters.ifinoctets;
value_len = sizeof(*value_u32);
break;
case 11: /* ifInUcastPkts */
*value_u32 = netif->mib2_counters.ifinucastpkts;
value_len = sizeof(*value_u32);
break;
case 12: /* ifInNUcastPkts */
*value_u32 = netif->mib2_counters.ifinnucastpkts;
value_len = sizeof(*value_u32);
break;
case 13: /* ifInDiscards */
*value_u32 = netif->mib2_counters.ifindiscards;
value_len = sizeof(*value_u32);
break;
case 14: /* ifInErrors */
*value_u32 = netif->mib2_counters.ifinerrors;
value_len = sizeof(*value_u32);
break;
case 15: /* ifInUnkownProtos */
*value_u32 = netif->mib2_counters.ifinunknownprotos;
value_len = sizeof(*value_u32);
break;
case 16: /* ifOutOctets */
*value_u32 = netif->mib2_counters.ifoutoctets;
value_len = sizeof(*value_u32);
break;
case 17: /* ifOutUcastPkts */
*value_u32 = netif->mib2_counters.ifoutucastpkts;
value_len = sizeof(*value_u32);
break;
case 18: /* ifOutNUcastPkts */
*value_u32 = netif->mib2_counters.ifoutnucastpkts;
value_len = sizeof(*value_u32);
break;
case 19: /* ifOutDiscarts */
*value_u32 = netif->mib2_counters.ifoutdiscards;
value_len = sizeof(*value_u32);
break;
case 20: /* ifOutErrors */
*value_u32 = netif->mib2_counters.ifouterrors;
value_len = sizeof(*value_u32);
break;
case 21: /* ifOutQLen */
*value_u32 = iftable_ifOutQLen;
value_len = sizeof(*value_u32);
break;
/** @note returning zeroDotZero (0.0) no media specific MIB support */
case 22: /* ifSpecific */
value_len = snmp_zero_dot_zero.len * sizeof(u32_t);
MEMCPY(value, snmp_zero_dot_zero.id, value_len);
break;
default:
return 0;
}
return value_len;
}
#if !SNMP_SAFE_REQUESTS
static snmp_err_t
interfaces_Table_set_test(struct snmp_node_instance* instance, u16_t len, void *value)
{
s32_t *sint_ptr = (s32_t*)value;
/* stack should never call this method for another column,
because all other columns are set to readonly */
LWIP_ASSERT("Invalid column", (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id) == 7));
LWIP_UNUSED_ARG(len);
if (*sint_ptr == 1 || *sint_ptr == 2) {
return SNMP_ERR_NOERROR;
}
return SNMP_ERR_WRONGVALUE;
}
static snmp_err_t
interfaces_Table_set_value(struct snmp_node_instance* instance, u16_t len, void *value)
{
struct netif *netif = (struct netif*)instance->reference.ptr;
s32_t *sint_ptr = (s32_t*)value;
/* stack should never call this method for another column,
because all other columns are set to readonly */
LWIP_ASSERT("Invalid column", (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id) == 7));
LWIP_UNUSED_ARG(len);
if (*sint_ptr == 1) {
netif_set_up(netif);
} else if (*sint_ptr == 2) {
netif_set_down(netif);
}
return SNMP_ERR_NOERROR;
}
#endif /* SNMP_SAFE_REQUESTS */
static const struct snmp_scalar_node interfaces_Number = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_INTEGER, interfaces_get_value);
static const struct snmp_table_col_def interfaces_Table_columns[] = {
{ 1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifIndex */
{ 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifDescr */
{ 3, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifType */
{ 4, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifMtu */
{ 5, SNMP_ASN1_TYPE_GAUGE, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifSpeed */
{ 6, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifPhysAddress */
#if !SNMP_SAFE_REQUESTS
{ 7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE }, /* ifAdminStatus */
#else
{ 7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifAdminStatus */
#endif
{ 8, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOperStatus */
{ 9, SNMP_ASN1_TYPE_TIMETICKS, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifLastChange */
{ 10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInOctets */
{ 11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInUcastPkts */
{ 12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInNUcastPkts */
{ 13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInDiscarts */
{ 14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInErrors */
{ 15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInUnkownProtos */
{ 16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutOctets */
{ 17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutUcastPkts */
{ 18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutNUcastPkts */
{ 19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutDiscarts */
{ 20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutErrors */
{ 21, SNMP_ASN1_TYPE_GAUGE, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutQLen */
{ 22, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY } /* ifSpecific */
};
#if !SNMP_SAFE_REQUESTS
static const struct snmp_table_node interfaces_Table = SNMP_TABLE_CREATE(
2, interfaces_Table_columns,
interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance,
interfaces_Table_get_value, interfaces_Table_set_test, interfaces_Table_set_value);
#else
static const struct snmp_table_node interfaces_Table = SNMP_TABLE_CREATE(
2, interfaces_Table_columns,
interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance,
interfaces_Table_get_value, NULL, NULL);
#endif
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
CREATE_LWIP_SYNC_NODE(1, interfaces_Number)
CREATE_LWIP_SYNC_NODE(2, interfaces_Table)
static const struct snmp_node* const interface_nodes[] = {
&SYNC_NODE_NAME(interfaces_Number).node.node,
&SYNC_NODE_NAME(interfaces_Table).node.node
};
const struct snmp_tree_node snmp_mib2_interface_root = SNMP_CREATE_TREE_NODE(2, interface_nodes);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */

View File

@@ -1,743 +0,0 @@
/**
* @file
* Management Information Base II (RFC1213) IP objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/stats.h"
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/etharp.h"
#if LWIP_SNMP && SNMP_LWIP_MIB2
#if SNMP_USE_NETCONN
#define SYNC_NODE_NAME(node_name) node_name ## _synced
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
#else
#define SYNC_NODE_NAME(node_name) node_name
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
#endif
#if LWIP_IPV4
/* --- ip .1.3.6.1.2.1.4 ----------------------------------------------------- */
static s16_t
ip_get_value(struct snmp_node_instance* instance, void* value)
{
s32_t* sint_ptr = (s32_t*)value;
u32_t* uint_ptr = (u32_t*)value;
switch (instance->node->oid) {
case 1: /* ipForwarding */
#if IP_FORWARD
/* forwarding */
*sint_ptr = 1;
#else
/* not-forwarding */
*sint_ptr = 2;
#endif
return sizeof(*sint_ptr);
case 2: /* ipDefaultTTL */
*sint_ptr = IP_DEFAULT_TTL;
return sizeof(*sint_ptr);
case 3: /* ipInReceives */
*uint_ptr = STATS_GET(mib2.ipinreceives);
return sizeof(*uint_ptr);
case 4: /* ipInHdrErrors */
*uint_ptr = STATS_GET(mib2.ipinhdrerrors);
return sizeof(*uint_ptr);
case 5: /* ipInAddrErrors */
*uint_ptr = STATS_GET(mib2.ipinaddrerrors);
return sizeof(*uint_ptr);
case 6: /* ipForwDatagrams */
*uint_ptr = STATS_GET(mib2.ipforwdatagrams);
return sizeof(*uint_ptr);
case 7: /* ipInUnknownProtos */
*uint_ptr = STATS_GET(mib2.ipinunknownprotos);
return sizeof(*uint_ptr);
case 8: /* ipInDiscards */
*uint_ptr = STATS_GET(mib2.ipindiscards);
return sizeof(*uint_ptr);
case 9: /* ipInDelivers */
*uint_ptr = STATS_GET(mib2.ipindelivers);
return sizeof(*uint_ptr);
case 10: /* ipOutRequests */
*uint_ptr = STATS_GET(mib2.ipoutrequests);
return sizeof(*uint_ptr);
case 11: /* ipOutDiscards */
*uint_ptr = STATS_GET(mib2.ipoutdiscards);
return sizeof(*uint_ptr);
case 12: /* ipOutNoRoutes */
*uint_ptr = STATS_GET(mib2.ipoutnoroutes);
return sizeof(*uint_ptr);
case 13: /* ipReasmTimeout */
#if IP_REASSEMBLY
*sint_ptr = IP_REASS_MAXAGE;
#else
*sint_ptr = 0;
#endif
return sizeof(*sint_ptr);
case 14: /* ipReasmReqds */
*uint_ptr = STATS_GET(mib2.ipreasmreqds);
return sizeof(*uint_ptr);
case 15: /* ipReasmOKs */
*uint_ptr = STATS_GET(mib2.ipreasmoks);
return sizeof(*uint_ptr);
case 16: /* ipReasmFails */
*uint_ptr = STATS_GET(mib2.ipreasmfails);
return sizeof(*uint_ptr);
case 17: /* ipFragOKs */
*uint_ptr = STATS_GET(mib2.ipfragoks);
return sizeof(*uint_ptr);
case 18: /* ipFragFails */
*uint_ptr = STATS_GET(mib2.ipfragfails);
return sizeof(*uint_ptr);
case 19: /* ipFragCreates */
*uint_ptr = STATS_GET(mib2.ipfragcreates);
return sizeof(*uint_ptr);
case 23: /* ipRoutingDiscards: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
break;
}
return 0;
}
/**
* Test ip object value before setting.
*
* @param instance node instance
* @param len return value space (in bytes)
* @param value points to (varbind) space to copy value from.
*
* @note we allow set if the value matches the hardwired value,
* otherwise return badvalue.
*/
static snmp_err_t
ip_set_test(struct snmp_node_instance* instance, u16_t len, void *value)
{
snmp_err_t ret = SNMP_ERR_WRONGVALUE;
s32_t *sint_ptr = (s32_t*)value;
LWIP_UNUSED_ARG(len);
switch (instance->node->oid) {
case 1: /* ipForwarding */
#if IP_FORWARD
/* forwarding */
if (*sint_ptr == 1)
#else
/* not-forwarding */
if (*sint_ptr == 2)
#endif
{
ret = SNMP_ERR_NOERROR;
}
break;
case 2: /* ipDefaultTTL */
if (*sint_ptr == IP_DEFAULT_TTL) {
ret = SNMP_ERR_NOERROR;
}
break;
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_set_test(): unknown id: %"S32_F"\n", instance->node->oid));
break;
}
return ret;
}
static snmp_err_t
ip_set_value(struct snmp_node_instance* instance, u16_t len, void *value)
{
LWIP_UNUSED_ARG(instance);
LWIP_UNUSED_ARG(len);
LWIP_UNUSED_ARG(value);
/* nothing to do here because in set_test we only accept values being the same as our own stored value -> no need to store anything */
return SNMP_ERR_NOERROR;
}
/* --- ipAddrTable --- */
/* list of allowed value ranges for incoming OID */
static const struct snmp_oid_range ip_AddrTable_oid_ranges[] = {
{ 0, 0xff }, /* IP A */
{ 0, 0xff }, /* IP B */
{ 0, 0xff }, /* IP C */
{ 0, 0xff } /* IP D */
};
static snmp_err_t
ip_AddrTable_get_cell_value_core(struct netif *netif, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
{
LWIP_UNUSED_ARG(value_len);
switch (*column) {
case 1: /* ipAdEntAddr */
value->u32 = netif_ip4_addr(netif)->addr;
break;
case 2: /* ipAdEntIfIndex */
value->u32 = netif_to_num(netif);
break;
case 3: /* ipAdEntNetMask */
value->u32 = netif_ip4_netmask(netif)->addr;
break;
case 4: /* ipAdEntBcastAddr */
/* lwIP oddity, there's no broadcast
address in the netif we can rely on */
value->u32 = IPADDR_BROADCAST & 1;
break;
case 5: /* ipAdEntReasmMaxSize */
#if IP_REASSEMBLY
/* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs,
* but only if receiving one fragmented packet at a time.
* The current solution is to calculate for 2 simultaneous packets...
*/
value->u32 = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) *
(PBUF_POOL_BUFSIZE - PBUF_LINK_ENCAPSULATION_HLEN - PBUF_LINK_HLEN - IP_HLEN)));
#else
/** @todo returning MTU would be a bad thing and
returning a wild guess like '576' isn't good either */
value->u32 = 0;
#endif
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
ip_AddrTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
{
ip4_addr_t ip;
struct netif *netif;
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, ip_AddrTable_oid_ranges, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges))) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* get IP from incoming OID */
snmp_oid_to_ip4(&row_oid[0], &ip); /* we know it succeeds because of oid_in_range check above */
/* find netif with requested ip */
netif = netif_list;
while (netif != NULL) {
if (ip4_addr_cmp(&ip, netif_ip4_addr(netif))) {
/* fill in object properties */
return ip_AddrTable_get_cell_value_core(netif, column, value, value_len);
}
netif = netif->next;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
ip_AddrTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
struct netif *netif;
struct snmp_next_oid_state state;
u32_t result_temp[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)];
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges));
/* iterate over all possible OIDs to find the next one */
netif = netif_list;
while (netif != NULL) {
u32_t test_oid[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)];
snmp_ip4_to_oid(netif_ip4_addr(netif), &test_oid[0]);
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges), netif);
netif = netif->next;
}
/* did we find a next one? */
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
/* fill in object properties */
return ip_AddrTable_get_cell_value_core((struct netif*)state.reference, column, value, value_len);
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
/* --- ipRouteTable --- */
/* list of allowed value ranges for incoming OID */
static const struct snmp_oid_range ip_RouteTable_oid_ranges[] = {
{ 0, 0xff }, /* IP A */
{ 0, 0xff }, /* IP B */
{ 0, 0xff }, /* IP C */
{ 0, 0xff }, /* IP D */
};
static snmp_err_t
ip_RouteTable_get_cell_value_core(struct netif *netif, u8_t default_route, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
{
switch (*column) {
case 1: /* ipRouteDest */
if (default_route) {
/* default rte has 0.0.0.0 dest */
value->u32 = IP4_ADDR_ANY4->addr;
} else {
/* netifs have netaddress dest */
ip4_addr_t tmp;
ip4_addr_get_network(&tmp, netif_ip4_addr(netif), netif_ip4_netmask(netif));
value->u32 = tmp.addr;
}
break;
case 2: /* ipRouteIfIndex */
value->u32 = netif_to_num(netif);
break;
case 3: /* ipRouteMetric1 */
if (default_route) {
value->s32 = 1; /* default */
} else {
value->s32 = 0; /* normal */
}
break;
case 4: /* ipRouteMetric2 */
case 5: /* ipRouteMetric3 */
case 6: /* ipRouteMetric4 */
value->s32 = -1; /* none */
break;
case 7: /* ipRouteNextHop */
if (default_route) {
/* default rte: gateway */
value->u32 = netif_ip4_gw(netif)->addr;
} else {
/* other rtes: netif ip_addr */
value->u32 = netif_ip4_addr(netif)->addr;
}
break;
case 8: /* ipRouteType */
if (default_route) {
/* default rte is indirect */
value->u32 = 4; /* indirect */
} else {
/* other rtes are direct */
value->u32 = 3; /* direct */
}
break;
case 9: /* ipRouteProto */
/* locally defined routes */
value->u32 = 2; /* local */
break;
case 10: /* ipRouteAge */
/* @todo (sysuptime - timestamp last change) / 100 */
value->u32 = 0;
break;
case 11: /* ipRouteMask */
if (default_route) {
/* default rte use 0.0.0.0 mask */
value->u32 = IP4_ADDR_ANY4->addr;
} else {
/* other rtes use netmask */
value->u32 = netif_ip4_netmask(netif)->addr;
}
break;
case 12: /* ipRouteMetric5 */
value->s32 = -1; /* none */
break;
case 13: /* ipRouteInfo */
value->const_ptr = snmp_zero_dot_zero.id;
*value_len = snmp_zero_dot_zero.len * sizeof(u32_t);
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
ip_RouteTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
{
ip4_addr_t test_ip;
struct netif *netif;
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, ip_RouteTable_oid_ranges, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges))) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* get IP and port from incoming OID */
snmp_oid_to_ip4(&row_oid[0], &test_ip); /* we know it succeeds because of oid_in_range check above */
/* default route is on default netif */
if (ip4_addr_isany_val(test_ip) && (netif_default != NULL)) {
/* fill in object properties */
return ip_RouteTable_get_cell_value_core(netif_default, 1, column, value, value_len);
}
/* find netif with requested route */
netif = netif_list;
while (netif != NULL) {
ip4_addr_t dst;
ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif));
if (ip4_addr_cmp(&dst, &test_ip)) {
/* fill in object properties */
return ip_RouteTable_get_cell_value_core(netif, 0, column, value, value_len);
}
netif = netif->next;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
ip_RouteTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
struct netif *netif;
struct snmp_next_oid_state state;
u32_t result_temp[LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges)];
u32_t test_oid[LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges)];
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges));
/* check default route */
if (netif_default != NULL) {
snmp_ip4_to_oid(IP4_ADDR_ANY4, &test_oid[0]);
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges), netif_default);
}
/* iterate over all possible OIDs to find the next one */
netif = netif_list;
while (netif != NULL) {
ip4_addr_t dst;
ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif));
/* check generated OID: is it a candidate for the next one? */
if (!ip4_addr_isany_val(dst)) {
snmp_ip4_to_oid(&dst, &test_oid[0]);
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges), netif);
}
netif = netif->next;
}
/* did we find a next one? */
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
ip4_addr_t dst;
snmp_oid_to_ip4(&result_temp[0], &dst);
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
/* fill in object properties */
return ip_RouteTable_get_cell_value_core((struct netif*)state.reference, ip4_addr_isany_val(dst), column, value, value_len);
} else {
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
}
#if LWIP_ARP && LWIP_IPV4
/* --- ipNetToMediaTable --- */
/* list of allowed value ranges for incoming OID */
static const struct snmp_oid_range ip_NetToMediaTable_oid_ranges[] = {
{ 1, 0xff }, /* IfIndex */
{ 0, 0xff }, /* IP A */
{ 0, 0xff }, /* IP B */
{ 0, 0xff }, /* IP C */
{ 0, 0xff } /* IP D */
};
static snmp_err_t
ip_NetToMediaTable_get_cell_value_core(u8_t arp_table_index, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
{
ip4_addr_t *ip;
struct netif *netif;
struct eth_addr *ethaddr;
etharp_get_entry(arp_table_index, &ip, &netif, &ethaddr);
/* value */
switch (*column) {
case 1: /* atIfIndex / ipNetToMediaIfIndex */
value->u32 = netif_to_num(netif);
break;
case 2: /* atPhysAddress / ipNetToMediaPhysAddress */
value->ptr = ethaddr;
*value_len = sizeof(*ethaddr);
break;
case 3: /* atNetAddress / ipNetToMediaNetAddress */
value->u32 = ip->addr;
break;
case 4: /* ipNetToMediaType */
value->u32 = 3; /* dynamic*/
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
ip_NetToMediaTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
{
ip4_addr_t ip_in;
u8_t netif_index;
u8_t i;
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, ip_NetToMediaTable_oid_ranges, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges))) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* get IP from incoming OID */
netif_index = (u8_t)row_oid[0];
snmp_oid_to_ip4(&row_oid[1], &ip_in); /* we know it succeeds because of oid_in_range check above */
/* find requested entry */
for (i=0; i<ARP_TABLE_SIZE; i++) {
ip4_addr_t *ip;
struct netif *netif;
struct eth_addr *ethaddr;
if (etharp_get_entry(i, &ip, &netif, &ethaddr)) {
if ((netif_index == netif_to_num(netif)) && ip4_addr_cmp(&ip_in, ip)) {
/* fill in object properties */
return ip_NetToMediaTable_get_cell_value_core(i, column, value, value_len);
}
}
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
ip_NetToMediaTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
u8_t i;
struct snmp_next_oid_state state;
u32_t result_temp[LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges)];
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges));
/* iterate over all possible OIDs to find the next one */
for (i=0; i<ARP_TABLE_SIZE; i++) {
ip4_addr_t *ip;
struct netif *netif;
struct eth_addr *ethaddr;
if (etharp_get_entry(i, &ip, &netif, &ethaddr)) {
u32_t test_oid[LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges)];
test_oid[0] = netif_to_num(netif);
snmp_ip4_to_oid(ip, &test_oid[1]);
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges), LWIP_PTR_NUMERIC_CAST(void*, i));
}
}
/* did we find a next one? */
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
/* fill in object properties */
return ip_NetToMediaTable_get_cell_value_core(LWIP_PTR_NUMERIC_CAST(u8_t, state.reference), column, value, value_len);
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
#endif /* LWIP_ARP && LWIP_IPV4 */
static const struct snmp_scalar_node ip_Forwarding = SNMP_SCALAR_CREATE_NODE(1, SNMP_NODE_INSTANCE_READ_WRITE, SNMP_ASN1_TYPE_INTEGER, ip_get_value, ip_set_test, ip_set_value);
static const struct snmp_scalar_node ip_DefaultTTL = SNMP_SCALAR_CREATE_NODE(2, SNMP_NODE_INSTANCE_READ_WRITE, SNMP_ASN1_TYPE_INTEGER, ip_get_value, ip_set_test, ip_set_value);
static const struct snmp_scalar_node ip_InReceives = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_InHdrErrors = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_InAddrErrors = SNMP_SCALAR_CREATE_NODE_READONLY(5, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_ForwDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(6, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_InUnknownProtos = SNMP_SCALAR_CREATE_NODE_READONLY(7, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_InDiscards = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_InDelivers = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_OutRequests = SNMP_SCALAR_CREATE_NODE_READONLY(10, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_OutDiscards = SNMP_SCALAR_CREATE_NODE_READONLY(11, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_OutNoRoutes = SNMP_SCALAR_CREATE_NODE_READONLY(12, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_ReasmTimeout = SNMP_SCALAR_CREATE_NODE_READONLY(13, SNMP_ASN1_TYPE_INTEGER, ip_get_value);
static const struct snmp_scalar_node ip_ReasmReqds = SNMP_SCALAR_CREATE_NODE_READONLY(14, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_ReasmOKs = SNMP_SCALAR_CREATE_NODE_READONLY(15, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_ReasmFails = SNMP_SCALAR_CREATE_NODE_READONLY(16, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_FragOKs = SNMP_SCALAR_CREATE_NODE_READONLY(17, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_FragFails = SNMP_SCALAR_CREATE_NODE_READONLY(18, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_FragCreates = SNMP_SCALAR_CREATE_NODE_READONLY(19, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_RoutingDiscards = SNMP_SCALAR_CREATE_NODE_READONLY(23, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_table_simple_col_def ip_AddrTable_columns[] = {
{ 1, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipAdEntAddr */
{ 2, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipAdEntIfIndex */
{ 3, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipAdEntNetMask */
{ 4, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipAdEntBcastAddr */
{ 5, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* ipAdEntReasmMaxSize */
};
static const struct snmp_table_simple_node ip_AddrTable = SNMP_TABLE_CREATE_SIMPLE(20, ip_AddrTable_columns, ip_AddrTable_get_cell_value, ip_AddrTable_get_next_cell_instance_and_value);
static const struct snmp_table_simple_col_def ip_RouteTable_columns[] = {
{ 1, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteDest */
{ 2, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteIfIndex */
{ 3, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric1 */
{ 4, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric2 */
{ 5, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric3 */
{ 6, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric4 */
{ 7, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteNextHop */
{ 8, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteType */
{ 9, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteProto */
{ 10, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteAge */
{ 11, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteMask */
{ 12, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric5 */
{ 13, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_VARIANT_VALUE_TYPE_PTR } /* ipRouteInfo */
};
static const struct snmp_table_simple_node ip_RouteTable = SNMP_TABLE_CREATE_SIMPLE(21, ip_RouteTable_columns, ip_RouteTable_get_cell_value, ip_RouteTable_get_next_cell_instance_and_value);
#endif /* LWIP_IPV4 */
#if LWIP_ARP && LWIP_IPV4
static const struct snmp_table_simple_col_def ip_NetToMediaTable_columns[] = {
{ 1, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipNetToMediaIfIndex */
{ 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_VARIANT_VALUE_TYPE_PTR }, /* ipNetToMediaPhysAddress */
{ 3, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipNetToMediaNetAddress */
{ 4, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* ipNetToMediaType */
};
static const struct snmp_table_simple_node ip_NetToMediaTable = SNMP_TABLE_CREATE_SIMPLE(22, ip_NetToMediaTable_columns, ip_NetToMediaTable_get_cell_value, ip_NetToMediaTable_get_next_cell_instance_and_value);
#endif /* LWIP_ARP && LWIP_IPV4 */
#if LWIP_IPV4
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
CREATE_LWIP_SYNC_NODE( 1, ip_Forwarding)
CREATE_LWIP_SYNC_NODE( 2, ip_DefaultTTL)
CREATE_LWIP_SYNC_NODE( 3, ip_InReceives)
CREATE_LWIP_SYNC_NODE( 4, ip_InHdrErrors)
CREATE_LWIP_SYNC_NODE( 5, ip_InAddrErrors)
CREATE_LWIP_SYNC_NODE( 6, ip_ForwDatagrams)
CREATE_LWIP_SYNC_NODE( 7, ip_InUnknownProtos)
CREATE_LWIP_SYNC_NODE( 8, ip_InDiscards)
CREATE_LWIP_SYNC_NODE( 9, ip_InDelivers)
CREATE_LWIP_SYNC_NODE(10, ip_OutRequests)
CREATE_LWIP_SYNC_NODE(11, ip_OutDiscards)
CREATE_LWIP_SYNC_NODE(12, ip_OutNoRoutes)
CREATE_LWIP_SYNC_NODE(13, ip_ReasmTimeout)
CREATE_LWIP_SYNC_NODE(14, ip_ReasmReqds)
CREATE_LWIP_SYNC_NODE(15, ip_ReasmOKs)
CREATE_LWIP_SYNC_NODE(15, ip_ReasmFails)
CREATE_LWIP_SYNC_NODE(17, ip_FragOKs)
CREATE_LWIP_SYNC_NODE(18, ip_FragFails)
CREATE_LWIP_SYNC_NODE(19, ip_FragCreates)
CREATE_LWIP_SYNC_NODE(20, ip_AddrTable)
CREATE_LWIP_SYNC_NODE(21, ip_RouteTable)
#if LWIP_ARP
CREATE_LWIP_SYNC_NODE(22, ip_NetToMediaTable)
#endif /* LWIP_ARP */
CREATE_LWIP_SYNC_NODE(23, ip_RoutingDiscards)
static const struct snmp_node* const ip_nodes[] = {
&SYNC_NODE_NAME(ip_Forwarding).node.node,
&SYNC_NODE_NAME(ip_DefaultTTL).node.node,
&SYNC_NODE_NAME(ip_InReceives).node.node,
&SYNC_NODE_NAME(ip_InHdrErrors).node.node,
&SYNC_NODE_NAME(ip_InAddrErrors).node.node,
&SYNC_NODE_NAME(ip_ForwDatagrams).node.node,
&SYNC_NODE_NAME(ip_InUnknownProtos).node.node,
&SYNC_NODE_NAME(ip_InDiscards).node.node,
&SYNC_NODE_NAME(ip_InDelivers).node.node,
&SYNC_NODE_NAME(ip_OutRequests).node.node,
&SYNC_NODE_NAME(ip_OutDiscards).node.node,
&SYNC_NODE_NAME(ip_OutNoRoutes).node.node,
&SYNC_NODE_NAME(ip_ReasmTimeout).node.node,
&SYNC_NODE_NAME(ip_ReasmReqds).node.node,
&SYNC_NODE_NAME(ip_ReasmOKs).node.node,
&SYNC_NODE_NAME(ip_ReasmFails).node.node,
&SYNC_NODE_NAME(ip_FragOKs).node.node,
&SYNC_NODE_NAME(ip_FragFails).node.node,
&SYNC_NODE_NAME(ip_FragCreates).node.node,
&SYNC_NODE_NAME(ip_AddrTable).node.node,
&SYNC_NODE_NAME(ip_RouteTable).node.node,
#if LWIP_ARP
&SYNC_NODE_NAME(ip_NetToMediaTable).node.node,
#endif /* LWIP_ARP */
&SYNC_NODE_NAME(ip_RoutingDiscards).node.node
};
const struct snmp_tree_node snmp_mib2_ip_root = SNMP_CREATE_TREE_NODE(4, ip_nodes);
#endif /* LWIP_IPV4 */
/* --- at .1.3.6.1.2.1.3 ----------------------------------------------------- */
#if LWIP_ARP && LWIP_IPV4
/* at node table is a subset of ip_nettomedia table (same rows but less columns) */
static const struct snmp_table_simple_col_def at_Table_columns[] = {
{ 1, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* atIfIndex */
{ 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_VARIANT_VALUE_TYPE_PTR }, /* atPhysAddress */
{ 3, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 } /* atNetAddress */
};
static const struct snmp_table_simple_node at_Table = SNMP_TABLE_CREATE_SIMPLE(1, at_Table_columns, ip_NetToMediaTable_get_cell_value, ip_NetToMediaTable_get_next_cell_instance_and_value);
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
CREATE_LWIP_SYNC_NODE(1, at_Table)
static const struct snmp_node* const at_nodes[] = {
&SYNC_NODE_NAME(at_Table).node.node
};
const struct snmp_tree_node snmp_mib2_at_root = SNMP_CREATE_TREE_NODE(3, at_nodes);
#endif /* LWIP_ARP && LWIP_IPV4 */
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */

View File

@@ -1,227 +0,0 @@
/**
* @file
* Management Information Base II (RFC1213) SNMP objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_scalar.h"
#if LWIP_SNMP && SNMP_LWIP_MIB2
#define MIB2_AUTH_TRAPS_ENABLED 1
#define MIB2_AUTH_TRAPS_DISABLED 2
/* --- snmp .1.3.6.1.2.1.11 ----------------------------------------------------- */
static s16_t
snmp_get_value(const struct snmp_scalar_array_node_def *node, void *value)
{
u32_t *uint_ptr = (u32_t*)value;
switch (node->oid) {
case 1: /* snmpInPkts */
*uint_ptr = snmp_stats.inpkts;
break;
case 2: /* snmpOutPkts */
*uint_ptr = snmp_stats.outpkts;
break;
case 3: /* snmpInBadVersions */
*uint_ptr = snmp_stats.inbadversions;
break;
case 4: /* snmpInBadCommunityNames */
*uint_ptr = snmp_stats.inbadcommunitynames;
break;
case 5: /* snmpInBadCommunityUses */
*uint_ptr = snmp_stats.inbadcommunityuses;
break;
case 6: /* snmpInASNParseErrs */
*uint_ptr = snmp_stats.inasnparseerrs;
break;
case 8: /* snmpInTooBigs */
*uint_ptr = snmp_stats.intoobigs;
break;
case 9: /* snmpInNoSuchNames */
*uint_ptr = snmp_stats.innosuchnames;
break;
case 10: /* snmpInBadValues */
*uint_ptr = snmp_stats.inbadvalues;
break;
case 11: /* snmpInReadOnlys */
*uint_ptr = snmp_stats.inreadonlys;
break;
case 12: /* snmpInGenErrs */
*uint_ptr = snmp_stats.ingenerrs;
break;
case 13: /* snmpInTotalReqVars */
*uint_ptr = snmp_stats.intotalreqvars;
break;
case 14: /* snmpInTotalSetVars */
*uint_ptr = snmp_stats.intotalsetvars;
break;
case 15: /* snmpInGetRequests */
*uint_ptr = snmp_stats.ingetrequests;
break;
case 16: /* snmpInGetNexts */
*uint_ptr = snmp_stats.ingetnexts;
break;
case 17: /* snmpInSetRequests */
*uint_ptr = snmp_stats.insetrequests;
break;
case 18: /* snmpInGetResponses */
*uint_ptr = snmp_stats.ingetresponses;
break;
case 19: /* snmpInTraps */
*uint_ptr = snmp_stats.intraps;
break;
case 20: /* snmpOutTooBigs */
*uint_ptr = snmp_stats.outtoobigs;
break;
case 21: /* snmpOutNoSuchNames */
*uint_ptr = snmp_stats.outnosuchnames;
break;
case 22: /* snmpOutBadValues */
*uint_ptr = snmp_stats.outbadvalues;
break;
case 24: /* snmpOutGenErrs */
*uint_ptr = snmp_stats.outgenerrs;
break;
case 25: /* snmpOutGetRequests */
*uint_ptr = snmp_stats.outgetrequests;
break;
case 26: /* snmpOutGetNexts */
*uint_ptr = snmp_stats.outgetnexts;
break;
case 27: /* snmpOutSetRequests */
*uint_ptr = snmp_stats.outsetrequests;
break;
case 28: /* snmpOutGetResponses */
*uint_ptr = snmp_stats.outgetresponses;
break;
case 29: /* snmpOutTraps */
*uint_ptr = snmp_stats.outtraps;
break;
case 30: /* snmpEnableAuthenTraps */
if (snmp_get_auth_traps_enabled() == SNMP_AUTH_TRAPS_DISABLED) {
*uint_ptr = MIB2_AUTH_TRAPS_DISABLED;
} else {
*uint_ptr = MIB2_AUTH_TRAPS_ENABLED;
}
break;
case 31: /* snmpSilentDrops */
*uint_ptr = 0; /* not supported */
break;
case 32: /* snmpProxyDrops */
*uint_ptr = 0; /* not supported */
break;
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_value(): unknown id: %"S32_F"\n", node->oid));
return 0;
}
return sizeof(*uint_ptr);
}
static snmp_err_t
snmp_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
{
snmp_err_t ret = SNMP_ERR_WRONGVALUE;
LWIP_UNUSED_ARG(len);
if (node->oid == 30) {
/* snmpEnableAuthenTraps */
s32_t *sint_ptr = (s32_t*)value;
/* we should have writable non-volatile mem here */
if ((*sint_ptr == MIB2_AUTH_TRAPS_DISABLED) || (*sint_ptr == MIB2_AUTH_TRAPS_ENABLED)) {
ret = SNMP_ERR_NOERROR;
}
}
return ret;
}
static snmp_err_t
snmp_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
{
LWIP_UNUSED_ARG(len);
if (node->oid == 30) {
/* snmpEnableAuthenTraps */
s32_t *sint_ptr = (s32_t*)value;
if (*sint_ptr == MIB2_AUTH_TRAPS_DISABLED) {
snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_DISABLED);
} else {
snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_ENABLED);
}
}
return SNMP_ERR_NOERROR;
}
/* the following nodes access variables in SNMP stack (snmp_stats) from SNMP worker thread -> OK, no sync needed */
static const struct snmp_scalar_array_node_def snmp_nodes[] = {
{ 1, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInPkts */
{ 2, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutPkts */
{ 3, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadVersions */
{ 4, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadCommunityNames */
{ 5, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadCommunityUses */
{ 6, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInASNParseErrs */
{ 8, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTooBigs */
{ 9, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInNoSuchNames */
{10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadValues */
{11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInReadOnlys */
{12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGenErrs */
{13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTotalReqVars */
{14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTotalSetVars */
{15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetRequests */
{16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetNexts */
{17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInSetRequests */
{18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetResponses */
{19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTraps */
{20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutTooBigs */
{21, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutNoSuchNames */
{22, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutBadValues */
{24, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGenErrs */
{25, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetRequests */
{26, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetNexts */
{27, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutSetRequests */
{28, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetResponses */
{29, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutTraps */
{30, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* snmpEnableAuthenTraps */
{31, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpSilentDrops */
{32, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY} /* snmpProxyDrops */
};
const struct snmp_scalar_array_node snmp_mib2_snmp_root = SNMP_SCALAR_CREATE_ARRAY_NODE(11, snmp_nodes, snmp_get_value, snmp_set_test, snmp_set_value);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */

View File

@@ -1,377 +0,0 @@
/**
* @file
* Management Information Base II (RFC1213) SYSTEM objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/sys.h"
#include <string.h>
#if LWIP_SNMP && SNMP_LWIP_MIB2
#if SNMP_USE_NETCONN
#define SYNC_NODE_NAME(node_name) node_name ## _synced
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
#else
#define SYNC_NODE_NAME(node_name) node_name
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
#endif
/* --- system .1.3.6.1.2.1.1 ----------------------------------------------------- */
/** mib-2.system.sysDescr */
static const u8_t sysdescr_default[] = SNMP_LWIP_MIB2_SYSDESC;
static const u8_t* sysdescr = sysdescr_default;
static const u16_t* sysdescr_len = NULL; /* use strlen for determining len */
/** mib-2.system.sysContact */
static const u8_t syscontact_default[] = SNMP_LWIP_MIB2_SYSCONTACT;
static const u8_t* syscontact = syscontact_default;
static const u16_t* syscontact_len = NULL; /* use strlen for determining len */
static u8_t* syscontact_wr = NULL; /* if writable, points to the same buffer as syscontact (required for correct constness) */
static u16_t* syscontact_wr_len = NULL; /* if writable, points to the same buffer as syscontact_len (required for correct constness) */
static u16_t syscontact_bufsize = 0; /* 0=not writable */
/** mib-2.system.sysName */
static const u8_t sysname_default[] = SNMP_LWIP_MIB2_SYSNAME;
static const u8_t* sysname = sysname_default;
static const u16_t* sysname_len = NULL; /* use strlen for determining len */
static u8_t* sysname_wr = NULL; /* if writable, points to the same buffer as sysname (required for correct constness) */
static u16_t* sysname_wr_len = NULL; /* if writable, points to the same buffer as sysname_len (required for correct constness) */
static u16_t sysname_bufsize = 0; /* 0=not writable */
/** mib-2.system.sysLocation */
static const u8_t syslocation_default[] = SNMP_LWIP_MIB2_SYSLOCATION;
static const u8_t* syslocation = syslocation_default;
static const u16_t* syslocation_len = NULL; /* use strlen for determining len */
static u8_t* syslocation_wr = NULL; /* if writable, points to the same buffer as syslocation (required for correct constness) */
static u16_t* syslocation_wr_len = NULL; /* if writable, points to the same buffer as syslocation_len (required for correct constness) */
static u16_t syslocation_bufsize = 0; /* 0=not writable */
/**
* @ingroup snmp_mib2
* Initializes sysDescr pointers.
*
* @param str if non-NULL then copy str pointer
* @param len points to string length, excluding zero terminator
*/
void
snmp_mib2_set_sysdescr(const u8_t *str, const u16_t *len)
{
if (str != NULL) {
sysdescr = str;
sysdescr_len = len;
}
}
/**
* @ingroup snmp_mib2
* Initializes sysContact pointers
*
* @param ocstr if non-NULL then copy str pointer
* @param ocstrlen points to string length, excluding zero terminator.
* if set to NULL it is assumed that ocstr is NULL-terminated.
* @param bufsize size of the buffer in bytes.
* (this is required because the buffer can be overwritten by snmp-set)
* if ocstrlen is NULL buffer needs space for terminating 0 byte.
* otherwise complete buffer is used for string.
* if bufsize is set to 0, the value is regarded as read-only.
*/
void
snmp_mib2_set_syscontact(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize)
{
if (ocstr != NULL) {
syscontact = ocstr;
syscontact_wr = ocstr;
syscontact_len = ocstrlen;
syscontact_wr_len = ocstrlen;
syscontact_bufsize = bufsize;
}
}
/**
* @ingroup snmp_mib2
* see \ref snmp_mib2_set_syscontact but set pointer to readonly memory
*/
void
snmp_mib2_set_syscontact_readonly(const u8_t *ocstr, const u16_t *ocstrlen)
{
if (ocstr != NULL) {
syscontact = ocstr;
syscontact_len = ocstrlen;
syscontact_wr = NULL;
syscontact_wr_len = NULL;
syscontact_bufsize = 0;
}
}
/**
* @ingroup snmp_mib2
* Initializes sysName pointers
*
* @param ocstr if non-NULL then copy str pointer
* @param ocstrlen points to string length, excluding zero terminator.
* if set to NULL it is assumed that ocstr is NULL-terminated.
* @param bufsize size of the buffer in bytes.
* (this is required because the buffer can be overwritten by snmp-set)
* if ocstrlen is NULL buffer needs space for terminating 0 byte.
* otherwise complete buffer is used for string.
* if bufsize is set to 0, the value is regarded as read-only.
*/
void
snmp_mib2_set_sysname(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize)
{
if (ocstr != NULL) {
sysname = ocstr;
sysname_wr = ocstr;
sysname_len = ocstrlen;
sysname_wr_len = ocstrlen;
sysname_bufsize = bufsize;
}
}
/**
* @ingroup snmp_mib2
* see \ref snmp_mib2_set_sysname but set pointer to readonly memory
*/
void
snmp_mib2_set_sysname_readonly(const u8_t *ocstr, const u16_t *ocstrlen)
{
if (ocstr != NULL) {
sysname = ocstr;
sysname_len = ocstrlen;
sysname_wr = NULL;
sysname_wr_len = NULL;
sysname_bufsize = 0;
}
}
/**
* @ingroup snmp_mib2
* Initializes sysLocation pointers
*
* @param ocstr if non-NULL then copy str pointer
* @param ocstrlen points to string length, excluding zero terminator.
* if set to NULL it is assumed that ocstr is NULL-terminated.
* @param bufsize size of the buffer in bytes.
* (this is required because the buffer can be overwritten by snmp-set)
* if ocstrlen is NULL buffer needs space for terminating 0 byte.
* otherwise complete buffer is used for string.
* if bufsize is set to 0, the value is regarded as read-only.
*/
void
snmp_mib2_set_syslocation(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize)
{
if (ocstr != NULL) {
syslocation = ocstr;
syslocation_wr = ocstr;
syslocation_len = ocstrlen;
syslocation_wr_len = ocstrlen;
syslocation_bufsize = bufsize;
}
}
/**
* @ingroup snmp_mib2
* see \ref snmp_mib2_set_syslocation but set pointer to readonly memory
*/
void
snmp_mib2_set_syslocation_readonly(const u8_t *ocstr, const u16_t *ocstrlen)
{
if (ocstr != NULL) {
syslocation = ocstr;
syslocation_len = ocstrlen;
syslocation_wr = NULL;
syslocation_wr_len = NULL;
syslocation_bufsize = 0;
}
}
static s16_t
system_get_value(const struct snmp_scalar_array_node_def *node, void *value)
{
const u8_t* var = NULL;
const s16_t* var_len;
u16_t result;
switch (node->oid) {
case 1: /* sysDescr */
var = sysdescr;
var_len = (const s16_t*)sysdescr_len;
break;
case 2: /* sysObjectID */
{
const struct snmp_obj_id* dev_enterprise_oid = snmp_get_device_enterprise_oid();
MEMCPY(value, dev_enterprise_oid->id, dev_enterprise_oid->len * sizeof(u32_t));
return dev_enterprise_oid->len * sizeof(u32_t);
}
case 3: /* sysUpTime */
MIB2_COPY_SYSUPTIME_TO((u32_t*)value);
return sizeof(u32_t);
case 4: /* sysContact */
var = syscontact;
var_len = (const s16_t*)syscontact_len;
break;
case 5: /* sysName */
var = sysname;
var_len = (const s16_t*)sysname_len;
break;
case 6: /* sysLocation */
var = syslocation;
var_len = (const s16_t*)syslocation_len;
break;
case 7: /* sysServices */
*(s32_t*)value = SNMP_SYSSERVICES;
return sizeof(s32_t);
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_value(): unknown id: %"S32_F"\n", node->oid));
return 0;
}
/* handle string values (OID 1,4,5 and 6) */
LWIP_ASSERT("", (value != NULL));
if (var_len == NULL) {
result = (s16_t)strlen((const char*)var);
} else {
result = *var_len;
}
MEMCPY(value, var, result);
return result;
}
static snmp_err_t
system_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
{
snmp_err_t ret = SNMP_ERR_WRONGVALUE;
const u16_t* var_bufsize = NULL;
const u16_t* var_wr_len;
LWIP_UNUSED_ARG(value);
switch (node->oid) {
case 4: /* sysContact */
var_bufsize = &syscontact_bufsize;
var_wr_len = syscontact_wr_len;
break;
case 5: /* sysName */
var_bufsize = &sysname_bufsize;
var_wr_len = sysname_wr_len;
break;
case 6: /* sysLocation */
var_bufsize = &syslocation_bufsize;
var_wr_len = syslocation_wr_len;
break;
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_set_test(): unknown id: %"S32_F"\n", node->oid));
return ret;
}
/* check if value is writable at all */
if (*var_bufsize > 0) {
if (var_wr_len == NULL) {
/* we have to take the terminating 0 into account */
if (len < *var_bufsize) {
ret = SNMP_ERR_NOERROR;
}
} else {
if (len <= *var_bufsize) {
ret = SNMP_ERR_NOERROR;
}
}
} else {
ret = SNMP_ERR_NOTWRITABLE;
}
return ret;
}
static snmp_err_t
system_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
{
u8_t* var_wr = NULL;
u16_t* var_wr_len;
switch (node->oid) {
case 4: /* sysContact */
var_wr = syscontact_wr;
var_wr_len = syscontact_wr_len;
break;
case 5: /* sysName */
var_wr = sysname_wr;
var_wr_len = sysname_wr_len;
break;
case 6: /* sysLocation */
var_wr = syslocation_wr;
var_wr_len = syslocation_wr_len;
break;
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_set_value(): unknown id: %"S32_F"\n", node->oid));
return SNMP_ERR_GENERROR;
}
/* no need to check size of target buffer, this was already done in set_test method */
LWIP_ASSERT("", var_wr != NULL);
MEMCPY(var_wr, value, len);
if (var_wr_len == NULL) {
/* add terminating 0 */
var_wr[len] = 0;
} else {
*var_wr_len = len;
}
return SNMP_ERR_NOERROR;
}
static const struct snmp_scalar_array_node_def system_nodes[] = {
{1, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysDescr */
{2, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysObjectID */
{3, SNMP_ASN1_TYPE_TIMETICKS, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysUpTime */
{4, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysContact */
{5, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysName */
{6, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysLocation */
{7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY} /* sysServices */
};
const struct snmp_scalar_array_node snmp_mib2_system_node = SNMP_SCALAR_CREATE_ARRAY_NODE(1, system_nodes, system_get_value, system_set_test, system_set_value);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */

View File

@@ -1,594 +0,0 @@
/**
* @file
* Management Information Base II (RFC1213) TCP objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/tcp.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/stats.h"
#include <string.h>
#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_TCP
#if SNMP_USE_NETCONN
#define SYNC_NODE_NAME(node_name) node_name ## _synced
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
#else
#define SYNC_NODE_NAME(node_name) node_name
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
#endif
/* --- tcp .1.3.6.1.2.1.6 ----------------------------------------------------- */
static s16_t
tcp_get_value(struct snmp_node_instance* instance, void* value)
{
u32_t *uint_ptr = (u32_t*)value;
s32_t *sint_ptr = (s32_t*)value;
switch (instance->node->oid) {
case 1: /* tcpRtoAlgorithm, vanj(4) */
*sint_ptr = 4;
return sizeof(*sint_ptr);
case 2: /* tcpRtoMin */
/* @todo not the actual value, a guess,
needs to be calculated */
*sint_ptr = 1000;
return sizeof(*sint_ptr);
case 3: /* tcpRtoMax */
/* @todo not the actual value, a guess,
needs to be calculated */
*sint_ptr = 60000;
return sizeof(*sint_ptr);
case 4: /* tcpMaxConn */
*sint_ptr = MEMP_NUM_TCP_PCB;
return sizeof(*sint_ptr);
case 5: /* tcpActiveOpens */
*uint_ptr = STATS_GET(mib2.tcpactiveopens);
return sizeof(*uint_ptr);
case 6: /* tcpPassiveOpens */
*uint_ptr = STATS_GET(mib2.tcppassiveopens);
return sizeof(*uint_ptr);
case 7: /* tcpAttemptFails */
*uint_ptr = STATS_GET(mib2.tcpattemptfails);
return sizeof(*uint_ptr);
case 8: /* tcpEstabResets */
*uint_ptr = STATS_GET(mib2.tcpestabresets);
return sizeof(*uint_ptr);
case 9: /* tcpCurrEstab */
{
u16_t tcpcurrestab = 0;
struct tcp_pcb *pcb = tcp_active_pcbs;
while (pcb != NULL) {
if ((pcb->state == ESTABLISHED) ||
(pcb->state == CLOSE_WAIT)) {
tcpcurrestab++;
}
pcb = pcb->next;
}
*uint_ptr = tcpcurrestab;
}
return sizeof(*uint_ptr);
case 10: /* tcpInSegs */
*uint_ptr = STATS_GET(mib2.tcpinsegs);
return sizeof(*uint_ptr);
case 11: /* tcpOutSegs */
*uint_ptr = STATS_GET(mib2.tcpoutsegs);
return sizeof(*uint_ptr);
case 12: /* tcpRetransSegs */
*uint_ptr = STATS_GET(mib2.tcpretranssegs);
return sizeof(*uint_ptr);
case 14: /* tcpInErrs */
*uint_ptr = STATS_GET(mib2.tcpinerrs);
return sizeof(*uint_ptr);
case 15: /* tcpOutRsts */
*uint_ptr = STATS_GET(mib2.tcpoutrsts);
return sizeof(*uint_ptr);
case 17: /* tcpHCInSegs */
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
return 2*sizeof(u32_t);
case 18: /* tcpHCOutSegs */
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
return 2*sizeof(u32_t);
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
break;
}
return 0;
}
/* --- tcpConnTable --- */
#if LWIP_IPV4
/* list of allowed value ranges for incoming OID */
static const struct snmp_oid_range tcp_ConnTable_oid_ranges[] = {
{ 0, 0xff }, /* IP A */
{ 0, 0xff }, /* IP B */
{ 0, 0xff }, /* IP C */
{ 0, 0xff }, /* IP D */
{ 0, 0xffff }, /* Port */
{ 0, 0xff }, /* IP A */
{ 0, 0xff }, /* IP B */
{ 0, 0xff }, /* IP C */
{ 0, 0xff }, /* IP D */
{ 0, 0xffff } /* Port */
};
static snmp_err_t
tcp_ConnTable_get_cell_value_core(struct tcp_pcb *pcb, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
{
LWIP_UNUSED_ARG(value_len);
/* value */
switch (*column) {
case 1: /* tcpConnState */
value->u32 = pcb->state + 1;
break;
case 2: /* tcpConnLocalAddress */
value->u32 = ip_2_ip4(&pcb->local_ip)->addr;
break;
case 3: /* tcpConnLocalPort */
value->u32 = pcb->local_port;
break;
case 4: /* tcpConnRemAddress */
if (pcb->state == LISTEN) {
value->u32 = IP4_ADDR_ANY4->addr;
} else {
value->u32 = ip_2_ip4(&pcb->remote_ip)->addr;
}
break;
case 5: /* tcpConnRemPort */
if (pcb->state == LISTEN) {
value->u32 = 0;
} else {
value->u32 = pcb->remote_port;
}
break;
default:
LWIP_ASSERT("invalid id", 0);
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
tcp_ConnTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
{
u8_t i;
ip4_addr_t local_ip;
ip4_addr_t remote_ip;
u16_t local_port;
u16_t remote_port;
struct tcp_pcb *pcb;
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, tcp_ConnTable_oid_ranges, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges))) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* get IPs and ports from incoming OID */
snmp_oid_to_ip4(&row_oid[0], &local_ip); /* we know it succeeds because of oid_in_range check above */
local_port = (u16_t)row_oid[4];
snmp_oid_to_ip4(&row_oid[5], &remote_ip); /* we know it succeeds because of oid_in_range check above */
remote_port = (u16_t)row_oid[9];
/* find tcp_pcb with requested ips and ports */
for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) {
pcb = *tcp_pcb_lists[i];
while (pcb != NULL) {
/* do local IP and local port match? */
if (IP_IS_V4_VAL(pcb->local_ip) &&
ip4_addr_cmp(&local_ip, ip_2_ip4(&pcb->local_ip)) && (local_port == pcb->local_port)) {
/* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */
if (pcb->state == LISTEN) {
if (ip4_addr_cmp(&remote_ip, IP4_ADDR_ANY4) && (remote_port == 0)) {
/* fill in object properties */
return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len);
}
} else {
if (IP_IS_V4_VAL(pcb->remote_ip) &&
ip4_addr_cmp(&remote_ip, ip_2_ip4(&pcb->remote_ip)) && (remote_port == pcb->remote_port)) {
/* fill in object properties */
return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len);
}
}
}
pcb = pcb->next;
}
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
tcp_ConnTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
u8_t i;
struct tcp_pcb *pcb;
struct snmp_next_oid_state state;
u32_t result_temp[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)];
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges));
/* iterate over all possible OIDs to find the next one */
for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) {
pcb = *tcp_pcb_lists[i];
while (pcb != NULL) {
u32_t test_oid[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)];
if (IP_IS_V4_VAL(pcb->local_ip)) {
snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]);
test_oid[4] = pcb->local_port;
/* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */
if (pcb->state == LISTEN) {
snmp_ip4_to_oid(IP4_ADDR_ANY4, &test_oid[5]);
test_oid[9] = 0;
} else {
if (IP_IS_V6_VAL(pcb->remote_ip)) { /* should never happen */
continue;
}
snmp_ip4_to_oid(ip_2_ip4(&pcb->remote_ip), &test_oid[5]);
test_oid[9] = pcb->remote_port;
}
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges), pcb);
}
pcb = pcb->next;
}
}
/* did we find a next one? */
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
/* fill in object properties */
return tcp_ConnTable_get_cell_value_core((struct tcp_pcb*)state.reference, column, value, value_len);
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
#endif /* LWIP_IPV4 */
/* --- tcpConnectionTable --- */
static snmp_err_t
tcp_ConnectionTable_get_cell_value_core(const u32_t* column, struct tcp_pcb *pcb, union snmp_variant_value* value)
{
/* all items except tcpConnectionState and tcpConnectionProcess are declared as not-accessible */
switch (*column) {
case 7: /* tcpConnectionState */
value->u32 = pcb->state + 1;
break;
case 8: /* tcpConnectionProcess */
value->u32 = 0; /* not supported */
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
tcp_ConnectionTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
{
ip_addr_t local_ip, remote_ip;
u16_t local_port, remote_port;
struct tcp_pcb *pcb;
u8_t idx = 0;
u8_t i;
struct tcp_pcb ** const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs};
LWIP_UNUSED_ARG(value_len);
/* tcpConnectionLocalAddressType + tcpConnectionLocalAddress + tcpConnectionLocalPort */
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port);
if (idx == 0) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* tcpConnectionRemAddressType + tcpConnectionRemAddress + tcpConnectionRemPort */
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &remote_ip, &remote_port);
if (idx == 0) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* find tcp_pcb with requested ip and port*/
for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_nonlisten_lists); i++) {
pcb = *tcp_pcb_nonlisten_lists[i];
while (pcb != NULL) {
if (ip_addr_cmp(&local_ip, &pcb->local_ip) &&
(local_port == pcb->local_port) &&
ip_addr_cmp(&remote_ip, &pcb->remote_ip) &&
(remote_port == pcb->remote_port)) {
/* fill in object properties */
return tcp_ConnectionTable_get_cell_value_core(column, pcb, value);
}
pcb = pcb->next;
}
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
tcp_ConnectionTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
struct tcp_pcb *pcb;
struct snmp_next_oid_state state;
/* 1x tcpConnectionLocalAddressType + 1x OID len + 16x tcpConnectionLocalAddress + 1x tcpConnectionLocalPort
* 1x tcpConnectionRemAddressType + 1x OID len + 16x tcpConnectionRemAddress + 1x tcpConnectionRemPort */
u32_t result_temp[38];
u8_t i;
struct tcp_pcb ** const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs};
LWIP_UNUSED_ARG(value_len);
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp));
/* iterate over all possible OIDs to find the next one */
for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_nonlisten_lists); i++) {
pcb = *tcp_pcb_nonlisten_lists[i];
while (pcb != NULL) {
u8_t idx = 0;
u32_t test_oid[LWIP_ARRAYSIZE(result_temp)];
/* tcpConnectionLocalAddressType + tcpConnectionLocalAddress + tcpConnectionLocalPort */
idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]);
/* tcpConnectionRemAddressType + tcpConnectionRemAddress + tcpConnectionRemPort */
idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]);
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, idx, pcb);
pcb = pcb->next;
}
}
/* did we find a next one? */
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
/* fill in object properties */
return tcp_ConnectionTable_get_cell_value_core(column, (struct tcp_pcb*)state.reference, value);
} else {
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
}
/* --- tcpListenerTable --- */
static snmp_err_t
tcp_ListenerTable_get_cell_value_core(const u32_t* column, union snmp_variant_value* value)
{
/* all items except tcpListenerProcess are declared as not-accessible */
switch (*column) {
case 4: /* tcpListenerProcess */
value->u32 = 0; /* not supported */
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
tcp_ListenerTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
{
ip_addr_t local_ip;
u16_t local_port;
struct tcp_pcb_listen *pcb;
u8_t idx = 0;
LWIP_UNUSED_ARG(value_len);
/* tcpListenerLocalAddressType + tcpListenerLocalAddress + tcpListenerLocalPort */
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port);
if (idx == 0) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* find tcp_pcb with requested ip and port*/
pcb = tcp_listen_pcbs.listen_pcbs;
while (pcb != NULL) {
if (ip_addr_cmp(&local_ip, &pcb->local_ip) &&
(local_port == pcb->local_port)) {
/* fill in object properties */
return tcp_ListenerTable_get_cell_value_core(column, value);
}
pcb = pcb->next;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
tcp_ListenerTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
struct tcp_pcb_listen *pcb;
struct snmp_next_oid_state state;
/* 1x tcpListenerLocalAddressType + 1x OID len + 16x tcpListenerLocalAddress + 1x tcpListenerLocalPort */
u32_t result_temp[19];
LWIP_UNUSED_ARG(value_len);
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp));
/* iterate over all possible OIDs to find the next one */
pcb = tcp_listen_pcbs.listen_pcbs;
while (pcb != NULL) {
u8_t idx = 0;
u32_t test_oid[LWIP_ARRAYSIZE(result_temp)];
/* tcpListenerLocalAddressType + tcpListenerLocalAddress + tcpListenerLocalPort */
idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]);
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, idx, NULL);
pcb = pcb->next;
}
/* did we find a next one? */
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
/* fill in object properties */
return tcp_ListenerTable_get_cell_value_core(column, value);
} else {
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
}
static const struct snmp_scalar_node tcp_RtoAlgorithm = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_INTEGER, tcp_get_value);
static const struct snmp_scalar_node tcp_RtoMin = SNMP_SCALAR_CREATE_NODE_READONLY(2, SNMP_ASN1_TYPE_INTEGER, tcp_get_value);
static const struct snmp_scalar_node tcp_RtoMax = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_INTEGER, tcp_get_value);
static const struct snmp_scalar_node tcp_MaxConn = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_INTEGER, tcp_get_value);
static const struct snmp_scalar_node tcp_ActiveOpens = SNMP_SCALAR_CREATE_NODE_READONLY(5, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_PassiveOpens = SNMP_SCALAR_CREATE_NODE_READONLY(6, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_AttemptFails = SNMP_SCALAR_CREATE_NODE_READONLY(7, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_EstabResets = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_CurrEstab = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_GAUGE, tcp_get_value);
static const struct snmp_scalar_node tcp_InSegs = SNMP_SCALAR_CREATE_NODE_READONLY(10, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_OutSegs = SNMP_SCALAR_CREATE_NODE_READONLY(11, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_RetransSegs = SNMP_SCALAR_CREATE_NODE_READONLY(12, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_InErrs = SNMP_SCALAR_CREATE_NODE_READONLY(14, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_OutRsts = SNMP_SCALAR_CREATE_NODE_READONLY(15, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_HCInSegs = SNMP_SCALAR_CREATE_NODE_READONLY(17, SNMP_ASN1_TYPE_COUNTER64, tcp_get_value);
static const struct snmp_scalar_node tcp_HCOutSegs = SNMP_SCALAR_CREATE_NODE_READONLY(18, SNMP_ASN1_TYPE_COUNTER64, tcp_get_value);
#if LWIP_IPV4
static const struct snmp_table_simple_col_def tcp_ConnTable_columns[] = {
{ 1, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnState */
{ 2, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnLocalAddress */
{ 3, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnLocalPort */
{ 4, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnRemAddress */
{ 5, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpConnRemPort */
};
static const struct snmp_table_simple_node tcp_ConnTable = SNMP_TABLE_CREATE_SIMPLE(13, tcp_ConnTable_columns, tcp_ConnTable_get_cell_value, tcp_ConnTable_get_next_cell_instance_and_value);
#endif /* LWIP_IPV4 */
static const struct snmp_table_simple_col_def tcp_ConnectionTable_columns[] = {
/* all items except tcpConnectionState and tcpConnectionProcess are declared as not-accessible */
{ 7, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnectionState */
{ 8, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpConnectionProcess */
};
static const struct snmp_table_simple_node tcp_ConnectionTable = SNMP_TABLE_CREATE_SIMPLE(19, tcp_ConnectionTable_columns, tcp_ConnectionTable_get_cell_value, tcp_ConnectionTable_get_next_cell_instance_and_value);
static const struct snmp_table_simple_col_def tcp_ListenerTable_columns[] = {
/* all items except tcpListenerProcess are declared as not-accessible */
{ 4, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpListenerProcess */
};
static const struct snmp_table_simple_node tcp_ListenerTable = SNMP_TABLE_CREATE_SIMPLE(20, tcp_ListenerTable_columns, tcp_ListenerTable_get_cell_value, tcp_ListenerTable_get_next_cell_instance_and_value);
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
CREATE_LWIP_SYNC_NODE( 1, tcp_RtoAlgorithm)
CREATE_LWIP_SYNC_NODE( 2, tcp_RtoMin)
CREATE_LWIP_SYNC_NODE( 3, tcp_RtoMax)
CREATE_LWIP_SYNC_NODE( 4, tcp_MaxConn)
CREATE_LWIP_SYNC_NODE( 5, tcp_ActiveOpens)
CREATE_LWIP_SYNC_NODE( 6, tcp_PassiveOpens)
CREATE_LWIP_SYNC_NODE( 7, tcp_AttemptFails)
CREATE_LWIP_SYNC_NODE( 8, tcp_EstabResets)
CREATE_LWIP_SYNC_NODE( 9, tcp_CurrEstab)
CREATE_LWIP_SYNC_NODE(10, tcp_InSegs)
CREATE_LWIP_SYNC_NODE(11, tcp_OutSegs)
CREATE_LWIP_SYNC_NODE(12, tcp_RetransSegs)
#if LWIP_IPV4
CREATE_LWIP_SYNC_NODE(13, tcp_ConnTable)
#endif /* LWIP_IPV4 */
CREATE_LWIP_SYNC_NODE(14, tcp_InErrs)
CREATE_LWIP_SYNC_NODE(15, tcp_OutRsts)
CREATE_LWIP_SYNC_NODE(17, tcp_HCInSegs)
CREATE_LWIP_SYNC_NODE(18, tcp_HCOutSegs)
CREATE_LWIP_SYNC_NODE(19, tcp_ConnectionTable)
CREATE_LWIP_SYNC_NODE(20, tcp_ListenerTable)
static const struct snmp_node* const tcp_nodes[] = {
&SYNC_NODE_NAME(tcp_RtoAlgorithm).node.node,
&SYNC_NODE_NAME(tcp_RtoMin).node.node,
&SYNC_NODE_NAME(tcp_RtoMax).node.node,
&SYNC_NODE_NAME(tcp_MaxConn).node.node,
&SYNC_NODE_NAME(tcp_ActiveOpens).node.node,
&SYNC_NODE_NAME(tcp_PassiveOpens).node.node,
&SYNC_NODE_NAME(tcp_AttemptFails).node.node,
&SYNC_NODE_NAME(tcp_EstabResets).node.node,
&SYNC_NODE_NAME(tcp_CurrEstab).node.node,
&SYNC_NODE_NAME(tcp_InSegs).node.node,
&SYNC_NODE_NAME(tcp_OutSegs).node.node,
&SYNC_NODE_NAME(tcp_RetransSegs).node.node,
#if LWIP_IPV4
&SYNC_NODE_NAME(tcp_ConnTable).node.node,
#endif /* LWIP_IPV4 */
&SYNC_NODE_NAME(tcp_InErrs).node.node,
&SYNC_NODE_NAME(tcp_OutRsts).node.node,
&SYNC_NODE_NAME(tcp_HCInSegs).node.node,
&SYNC_NODE_NAME(tcp_HCOutSegs).node.node,
&SYNC_NODE_NAME(tcp_ConnectionTable).node.node,
&SYNC_NODE_NAME(tcp_ListenerTable).node.node
};
const struct snmp_tree_node snmp_mib2_tcp_root = SNMP_CREATE_TREE_NODE(6, tcp_nodes);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_TCP */

View File

@@ -1,357 +0,0 @@
/**
* @file
* Management Information Base II (RFC1213) UDP objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/udp.h"
#include "lwip/stats.h"
#include <string.h>
#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP
#if SNMP_USE_NETCONN
#define SYNC_NODE_NAME(node_name) node_name ## _synced
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
#else
#define SYNC_NODE_NAME(node_name) node_name
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
#endif
/* --- udp .1.3.6.1.2.1.7 ----------------------------------------------------- */
static s16_t
udp_get_value(struct snmp_node_instance* instance, void* value)
{
u32_t *uint_ptr = (u32_t*)value;
switch (instance->node->oid) {
case 1: /* udpInDatagrams */
*uint_ptr = STATS_GET(mib2.udpindatagrams);
return sizeof(*uint_ptr);
case 2: /* udpNoPorts */
*uint_ptr = STATS_GET(mib2.udpnoports);
return sizeof(*uint_ptr);
case 3: /* udpInErrors */
*uint_ptr = STATS_GET(mib2.udpinerrors);
return sizeof(*uint_ptr);
case 4: /* udpOutDatagrams */
*uint_ptr = STATS_GET(mib2.udpoutdatagrams);
return sizeof(*uint_ptr);
case 8: /* udpHCInDatagrams */
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
return 2*sizeof(u32_t);
case 9: /* udpHCOutDatagrams */
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
return 2*sizeof(u32_t);
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
break;
}
return 0;
}
/* --- udpEndpointTable --- */
static snmp_err_t
udp_endpointTable_get_cell_value_core(const u32_t* column, union snmp_variant_value* value)
{
/* all items except udpEndpointProcess are declared as not-accessible */
switch (*column) {
case 8: /* udpEndpointProcess */
value->u32 = 0; /* not supported */
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
udp_endpointTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
{
ip_addr_t local_ip, remote_ip;
u16_t local_port, remote_port;
struct udp_pcb *pcb;
u8_t idx = 0;
LWIP_UNUSED_ARG(value_len);
/* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port);
if (idx == 0) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &remote_ip, &remote_port);
if (idx == 0) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* udpEndpointInstance */
if (row_oid_len < (idx+1)) {
return SNMP_ERR_NOSUCHINSTANCE;
}
if (row_oid[idx] != 0) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* find udp_pcb with requested ip and port*/
pcb = udp_pcbs;
while (pcb != NULL) {
if (ip_addr_cmp(&local_ip, &pcb->local_ip) &&
(local_port == pcb->local_port) &&
ip_addr_cmp(&remote_ip, &pcb->remote_ip) &&
(remote_port == pcb->remote_port)) {
/* fill in object properties */
return udp_endpointTable_get_cell_value_core(column, value);
}
pcb = pcb->next;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
udp_endpointTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
struct udp_pcb *pcb;
struct snmp_next_oid_state state;
/* 1x udpEndpointLocalAddressType + 1x OID len + 16x udpEndpointLocalAddress + 1x udpEndpointLocalPort +
* 1x udpEndpointRemoteAddressType + 1x OID len + 16x udpEndpointRemoteAddress + 1x udpEndpointRemotePort +
* 1x udpEndpointInstance = 39
*/
u32_t result_temp[39];
LWIP_UNUSED_ARG(value_len);
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp));
/* iterate over all possible OIDs to find the next one */
pcb = udp_pcbs;
while (pcb != NULL) {
u32_t test_oid[LWIP_ARRAYSIZE(result_temp)];
u8_t idx = 0;
/* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */
idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]);
/* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */
idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]);
test_oid[idx] = 0; /* udpEndpointInstance */
idx++;
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, idx, NULL);
pcb = pcb->next;
}
/* did we find a next one? */
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
/* fill in object properties */
return udp_endpointTable_get_cell_value_core(column, value);
} else {
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
}
/* --- udpTable --- */
#if LWIP_IPV4
/* list of allowed value ranges for incoming OID */
static const struct snmp_oid_range udp_Table_oid_ranges[] = {
{ 0, 0xff }, /* IP A */
{ 0, 0xff }, /* IP B */
{ 0, 0xff }, /* IP C */
{ 0, 0xff }, /* IP D */
{ 1, 0xffff } /* Port */
};
static snmp_err_t
udp_Table_get_cell_value_core(struct udp_pcb *pcb, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
{
LWIP_UNUSED_ARG(value_len);
switch (*column) {
case 1: /* udpLocalAddress */
/* set reference to PCB local IP and return a generic node that copies IP4 addresses */
value->u32 = ip_2_ip4(&pcb->local_ip)->addr;
break;
case 2: /* udpLocalPort */
/* set reference to PCB local port and return a generic node that copies u16_t values */
value->u32 = pcb->local_port;
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
udp_Table_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
{
ip4_addr_t ip;
u16_t port;
struct udp_pcb *pcb;
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, udp_Table_oid_ranges, LWIP_ARRAYSIZE(udp_Table_oid_ranges))) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* get IP and port from incoming OID */
snmp_oid_to_ip4(&row_oid[0], &ip); /* we know it succeeds because of oid_in_range check above */
port = (u16_t)row_oid[4];
/* find udp_pcb with requested ip and port*/
pcb = udp_pcbs;
while (pcb != NULL) {
if (IP_IS_V4_VAL(pcb->local_ip)) {
if (ip4_addr_cmp(&ip, ip_2_ip4(&pcb->local_ip)) && (port == pcb->local_port)) {
/* fill in object properties */
return udp_Table_get_cell_value_core(pcb, column, value, value_len);
}
}
pcb = pcb->next;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
udp_Table_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
struct udp_pcb *pcb;
struct snmp_next_oid_state state;
u32_t result_temp[LWIP_ARRAYSIZE(udp_Table_oid_ranges)];
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(udp_Table_oid_ranges));
/* iterate over all possible OIDs to find the next one */
pcb = udp_pcbs;
while (pcb != NULL) {
u32_t test_oid[LWIP_ARRAYSIZE(udp_Table_oid_ranges)];
if (IP_IS_V4_VAL(pcb->local_ip)) {
snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]);
test_oid[4] = pcb->local_port;
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(udp_Table_oid_ranges), pcb);
}
pcb = pcb->next;
}
/* did we find a next one? */
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
/* fill in object properties */
return udp_Table_get_cell_value_core((struct udp_pcb*)state.reference, column, value, value_len);
} else {
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
}
#endif /* LWIP_IPV4 */
static const struct snmp_scalar_node udp_inDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_COUNTER, udp_get_value);
static const struct snmp_scalar_node udp_noPorts = SNMP_SCALAR_CREATE_NODE_READONLY(2, SNMP_ASN1_TYPE_COUNTER, udp_get_value);
static const struct snmp_scalar_node udp_inErrors = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_COUNTER, udp_get_value);
static const struct snmp_scalar_node udp_outDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_COUNTER, udp_get_value);
static const struct snmp_scalar_node udp_HCInDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER64, udp_get_value);
static const struct snmp_scalar_node udp_HCOutDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_COUNTER64, udp_get_value);
#if LWIP_IPV4
static const struct snmp_table_simple_col_def udp_Table_columns[] = {
{ 1, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* udpLocalAddress */
{ 2, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* udpLocalPort */
};
static const struct snmp_table_simple_node udp_Table = SNMP_TABLE_CREATE_SIMPLE(5, udp_Table_columns, udp_Table_get_cell_value, udp_Table_get_next_cell_instance_and_value);
#endif /* LWIP_IPV4 */
static const struct snmp_table_simple_col_def udp_endpointTable_columns[] = {
/* all items except udpEndpointProcess are declared as not-accessible */
{ 8, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* udpEndpointProcess */
};
static const struct snmp_table_simple_node udp_endpointTable = SNMP_TABLE_CREATE_SIMPLE(7, udp_endpointTable_columns, udp_endpointTable_get_cell_value, udp_endpointTable_get_next_cell_instance_and_value);
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
CREATE_LWIP_SYNC_NODE(1, udp_inDatagrams)
CREATE_LWIP_SYNC_NODE(2, udp_noPorts)
CREATE_LWIP_SYNC_NODE(3, udp_inErrors)
CREATE_LWIP_SYNC_NODE(4, udp_outDatagrams)
#if LWIP_IPV4
CREATE_LWIP_SYNC_NODE(5, udp_Table)
#endif /* LWIP_IPV4 */
CREATE_LWIP_SYNC_NODE(7, udp_endpointTable)
CREATE_LWIP_SYNC_NODE(8, udp_HCInDatagrams)
CREATE_LWIP_SYNC_NODE(9, udp_HCOutDatagrams)
static const struct snmp_node* const udp_nodes[] = {
&SYNC_NODE_NAME(udp_inDatagrams).node.node,
&SYNC_NODE_NAME(udp_noPorts).node.node,
&SYNC_NODE_NAME(udp_inErrors).node.node,
&SYNC_NODE_NAME(udp_outDatagrams).node.node,
#if LWIP_IPV4
&SYNC_NODE_NAME(udp_Table).node.node,
#endif /* LWIP_IPV4 */
&SYNC_NODE_NAME(udp_endpointTable).node.node,
&SYNC_NODE_NAME(udp_HCInDatagrams).node.node,
&SYNC_NODE_NAME(udp_HCOutDatagrams).node.node
};
const struct snmp_tree_node snmp_mib2_udp_root = SNMP_CREATE_TREE_NODE(7, udp_nodes);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP */

File diff suppressed because it is too large Load Diff

View File

@@ -1,194 +0,0 @@
/**
* @file
* SNMP Agent message handling structures (internal API, do not use in client code).
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* Copyright (c) 2016 Elias Oenal.
* 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.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
* Martin Hentschel <info@cl-soft.de>
* Elias Oenal <lwip@eliasoenal.com>
*/
#ifndef LWIP_HDR_APPS_SNMP_MSG_H
#define LWIP_HDR_APPS_SNMP_MSG_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "snmp_pbuf_stream.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#if LWIP_SNMP_V3
#include "snmpv3_priv.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* The listen port of the SNMP agent. Clients have to make their requests to
this port. Most standard clients won't work if you change this! */
#ifndef SNMP_IN_PORT
#define SNMP_IN_PORT 161
#endif
/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't
work if you change this! */
#ifndef SNMP_TRAP_PORT
#define SNMP_TRAP_PORT 162
#endif
/* version defines used in PDU */
#define SNMP_VERSION_1 0
#define SNMP_VERSION_2c 1
#define SNMP_VERSION_3 3
struct snmp_varbind_enumerator
{
struct snmp_pbuf_stream pbuf_stream;
u16_t varbind_count;
};
typedef enum {
SNMP_VB_ENUMERATOR_ERR_OK = 0,
SNMP_VB_ENUMERATOR_ERR_EOVB = 1,
SNMP_VB_ENUMERATOR_ERR_ASN1ERROR = 2,
SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH = 3
} snmp_vb_enumerator_err_t;
void snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length);
snmp_vb_enumerator_err_t snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind);
struct snmp_request
{
/* Communication handle */
void *handle;
/* source IP address */
const ip_addr_t *source_ip;
/* source UDP port */
u16_t source_port;
/* incoming snmp version */
u8_t version;
/* community name (zero terminated) */
u8_t community[SNMP_MAX_COMMUNITY_STR_LEN + 1];
/* community string length (exclusive zero term) */
u16_t community_strlen;
/* request type */
u8_t request_type;
/* request ID */
s32_t request_id;
/* error status */
s32_t error_status;
/* error index */
s32_t error_index;
/* non-repeaters (getBulkRequest (SNMPv2c)) */
s32_t non_repeaters;
/* max-repetitions (getBulkRequest (SNMPv2c)) */
s32_t max_repetitions;
#if LWIP_SNMP_V3
s32_t msg_id;
s32_t msg_max_size;
u8_t msg_flags;
s32_t msg_security_model;
u8_t msg_authoritative_engine_id[SNMP_V3_MAX_ENGINE_ID_LENGTH];
u8_t msg_authoritative_engine_id_len;
s32_t msg_authoritative_engine_boots;
s32_t msg_authoritative_engine_time;
u8_t msg_user_name[SNMP_V3_MAX_USER_LENGTH];
u8_t msg_user_name_len;
u8_t msg_authentication_parameters[SNMP_V3_MAX_AUTH_PARAM_LENGTH];
u8_t msg_privacy_parameters[SNMP_V3_MAX_PRIV_PARAM_LENGTH];
u8_t context_engine_id[SNMP_V3_MAX_ENGINE_ID_LENGTH];
u8_t context_engine_id_len;
u8_t context_name[SNMP_V3_MAX_ENGINE_ID_LENGTH];
u8_t context_name_len;
#endif
struct pbuf *inbound_pbuf;
struct snmp_varbind_enumerator inbound_varbind_enumerator;
u16_t inbound_varbind_offset;
u16_t inbound_varbind_len;
u16_t inbound_padding_len;
struct pbuf *outbound_pbuf;
struct snmp_pbuf_stream outbound_pbuf_stream;
u16_t outbound_pdu_offset;
u16_t outbound_error_status_offset;
u16_t outbound_error_index_offset;
u16_t outbound_varbind_offset;
#if LWIP_SNMP_V3
u16_t outbound_msg_global_data_offset;
u16_t outbound_msg_global_data_end;
u16_t outbound_msg_security_parameters_str_offset;
u16_t outbound_msg_security_parameters_seq_offset;
u16_t outbound_msg_security_parameters_end;
u16_t outbound_msg_authentication_parameters_offset;
u16_t outbound_scoped_pdu_seq_offset;
u16_t outbound_scoped_pdu_string_offset;
#endif
u8_t value_buffer[SNMP_MAX_VALUE_SIZE];
};
/** A helper struct keeping length information about varbinds */
struct snmp_varbind_len
{
u8_t vb_len_len;
u16_t vb_value_len;
u8_t oid_len_len;
u16_t oid_value_len;
u8_t value_len_len;
u16_t value_value_len;
};
/** Agent community string */
extern const char *snmp_community;
/** Agent community string for write access */
extern const char *snmp_community_write;
/** handle for sending traps */
extern void* snmp_traps_handle;
void snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port);
err_t snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port);
u8_t snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result);
err_t snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len);
err_t snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_MSG_H */

View File

@@ -1,121 +0,0 @@
/**
* @file
* SNMP netconn frontend.
*/
/*
* 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.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP && SNMP_USE_NETCONN
#include <string.h>
#include "lwip/api.h"
#include "lwip/ip.h"
#include "lwip/udp.h"
#include "snmp_msg.h"
#include "lwip/sys.h"
/** SNMP netconn API worker thread */
static void
snmp_netconn_thread(void *arg)
{
struct netconn *conn;
struct netbuf *buf;
err_t err;
LWIP_UNUSED_ARG(arg);
/* Bind to SNMP port with default IP address */
#if LWIP_IPV6
conn = netconn_new(NETCONN_UDP_IPV6);
netconn_bind(conn, IP6_ADDR_ANY, SNMP_IN_PORT);
#else /* LWIP_IPV6 */
conn = netconn_new(NETCONN_UDP);
netconn_bind(conn, IP4_ADDR_ANY, SNMP_IN_PORT);
#endif /* LWIP_IPV6 */
LWIP_ERROR("snmp_netconn: invalid conn", (conn != NULL), return;);
snmp_traps_handle = conn;
do {
err = netconn_recv(conn, &buf);
if (err == ERR_OK) {
snmp_receive(conn, buf->p, &buf->addr, buf->port);
}
if (buf != NULL) {
netbuf_delete(buf);
}
} while(1);
}
err_t
snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port)
{
err_t result;
struct netbuf buf;
memset(&buf, 0, sizeof(buf));
buf.p = p;
result = netconn_sendto((struct netconn*)handle, &buf, dst, port);
return result;
}
u8_t
snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result)
{
struct netconn* conn = (struct netconn*)handle;
struct netif *dst_if;
const ip_addr_t* dst_ip;
LWIP_UNUSED_ARG(conn); /* unused in case of IPV4 only configuration */
ip_route_get_local_ip(&conn->pcb.udp->local_ip, dst, dst_if, dst_ip);
if ((dst_if != NULL) && (dst_ip != NULL)) {
ip_addr_copy(*result, *dst_ip);
return 1;
} else {
return 0;
}
}
/**
* Starts SNMP Agent.
*/
void
snmp_init(void)
{
sys_thread_new("snmp_netconn", snmp_netconn_thread, NULL, SNMP_STACK_SIZE, SNMP_THREAD_PRIO);
}
#endif /* LWIP_SNMP && SNMP_USE_NETCONN */

View File

@@ -1,156 +0,0 @@
/**
* @file
* SNMP pbuf stream wrapper implementation (internal API, do not use in client code).
*/
/*
* 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: Martin Hentschel <info@cl-soft.de>
*
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "snmp_pbuf_stream.h"
#include "lwip/def.h"
#include <string.h>
err_t
snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_t offset, u16_t length)
{
pbuf_stream->offset = offset;
pbuf_stream->length = length;
pbuf_stream->pbuf = p;
return ERR_OK;
}
err_t
snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data)
{
if (pbuf_stream->length == 0) {
return ERR_BUF;
}
if (pbuf_copy_partial(pbuf_stream->pbuf, data, 1, pbuf_stream->offset) == 0) {
return ERR_BUF;
}
pbuf_stream->offset++;
pbuf_stream->length--;
return ERR_OK;
}
err_t
snmp_pbuf_stream_write(struct snmp_pbuf_stream* pbuf_stream, u8_t data)
{
return snmp_pbuf_stream_writebuf(pbuf_stream, &data, 1);
}
err_t
snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf, u16_t buf_len)
{
if (pbuf_stream->length < buf_len) {
return ERR_BUF;
}
if (pbuf_take_at(pbuf_stream->pbuf, buf, buf_len, pbuf_stream->offset) != ERR_OK) {
return ERR_BUF;
}
pbuf_stream->offset += buf_len;
pbuf_stream->length -= buf_len;
return ERR_OK;
}
err_t
snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_stream* target_pbuf_stream, u16_t len)
{
if ((pbuf_stream == NULL) || (target_pbuf_stream == NULL)) {
return ERR_ARG;
}
if ((len > pbuf_stream->length) || (len > target_pbuf_stream->length)) {
return ERR_ARG;
}
if (len == 0) {
len = LWIP_MIN(pbuf_stream->length, target_pbuf_stream->length);
}
while (len > 0) {
u16_t chunk_len;
err_t err;
u16_t target_offset;
struct pbuf* pbuf = pbuf_skip(pbuf_stream->pbuf, pbuf_stream->offset, &target_offset);
if ((pbuf == NULL) || (pbuf->len == 0)) {
return ERR_BUF;
}
chunk_len = LWIP_MIN(len, pbuf->len);
err = snmp_pbuf_stream_writebuf(target_pbuf_stream, &((u8_t*)pbuf->payload)[target_offset], chunk_len);
if (err != ERR_OK) {
return err;
}
pbuf_stream->offset += chunk_len;
pbuf_stream->length -= chunk_len;
len -= chunk_len;
}
return ERR_OK;
}
err_t
snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset)
{
if ((offset < 0) || (offset > pbuf_stream->length)) {
/* we cannot seek backwards or forward behind stream end */
return ERR_ARG;
}
pbuf_stream->offset += (u16_t)offset;
pbuf_stream->length -= (u16_t)offset;
return ERR_OK;
}
err_t
snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream* pbuf_stream, u32_t offset)
{
s32_t rel_offset = offset - pbuf_stream->offset;
return snmp_pbuf_stream_seek(pbuf_stream, rel_offset);
}
#endif /* LWIP_SNMP */

View File

@@ -1,73 +0,0 @@
/**
* @file
* SNMP pbuf stream wrapper (internal API, do not use in client code).
*/
/*
* 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: Martin Hentschel <info@cl-soft.de>
*
*/
#ifndef LWIP_HDR_APPS_SNMP_PBUF_STREAM_H
#define LWIP_HDR_APPS_SNMP_PBUF_STREAM_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP
#include "lwip/err.h"
#include "lwip/pbuf.h"
#ifdef __cplusplus
extern "C" {
#endif
struct snmp_pbuf_stream
{
struct pbuf* pbuf;
u16_t offset;
u16_t length;
};
err_t snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_t offset, u16_t length);
err_t snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data);
err_t snmp_pbuf_stream_write(struct snmp_pbuf_stream* pbuf_stream, u8_t data);
err_t snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf, u16_t buf_len);
err_t snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_stream* target_pbuf_stream, u16_t len);
err_t snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset);
err_t snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream* pbuf_stream, u32_t offset);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_PBUF_STREAM_H */

View File

@@ -1,100 +0,0 @@
/**
* @file
* SNMP RAW API frontend.
*/
/*
* 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.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
*/
#include "lwip/apps/snmp_opts.h"
#include "lwip/ip_addr.h"
#if LWIP_SNMP && SNMP_USE_RAW
#include "lwip/udp.h"
#include "lwip/ip.h"
#include "snmp_msg.h"
/* lwIP UDP receive callback function */
static void
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
LWIP_UNUSED_ARG(arg);
snmp_receive(pcb, p, addr, port);
pbuf_free(p);
}
err_t
snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port)
{
return udp_sendto((struct udp_pcb*)handle, p, dst, port);
}
u8_t
snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result)
{
struct udp_pcb* udp_pcb = (struct udp_pcb*)handle;
struct netif *dst_if;
const ip_addr_t* dst_ip;
LWIP_UNUSED_ARG(udp_pcb); /* unused in case of IPV4 only configuration */
ip_route_get_local_ip(&udp_pcb->local_ip, dst, dst_if, dst_ip);
if ((dst_if != NULL) && (dst_ip != NULL)) {
ip_addr_copy(*result, *dst_ip);
return 1;
} else {
return 0;
}
}
/**
* @ingroup snmp_core
* Starts SNMP Agent.
* Allocates UDP pcb and binds it to IP_ANY_TYPE port 161.
*/
void
snmp_init(void)
{
err_t err;
struct udp_pcb *snmp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
LWIP_ERROR("snmp_raw: no PCB", (snmp_pcb != NULL), return;);
snmp_traps_handle = snmp_pcb;
udp_recv(snmp_pcb, snmp_recv, (void *)SNMP_IN_PORT);
err = udp_bind(snmp_pcb, IP_ANY_TYPE, SNMP_IN_PORT);
LWIP_ERROR("snmp_raw: Unable to bind PCB", (err == ERR_OK), return;);
}
#endif /* LWIP_SNMP && SNMP_USE_RAW */

View File

@@ -1,220 +0,0 @@
/**
* @file
* SNMP scalar node support 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: Martin Hentschel <info@cl-soft.de>
*
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_scalar.h"
#include "lwip/apps/snmp_core.h"
static s16_t snmp_scalar_array_get_value(struct snmp_node_instance* instance, void* value);
static snmp_err_t snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value);
static snmp_err_t snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value);
snmp_err_t
snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
const struct snmp_scalar_node* scalar_node = (const struct snmp_scalar_node*)(const void*)instance->node;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* scalar only has one dedicated instance: .0 */
if ((instance->instance_oid.len != 1) || (instance->instance_oid.id[0] != 0)) {
return SNMP_ERR_NOSUCHINSTANCE;
}
instance->access = scalar_node->access;
instance->asn1_type = scalar_node->asn1_type;
instance->get_value = scalar_node->get_value;
instance->set_test = scalar_node->set_test;
instance->set_value = scalar_node->set_value;
return SNMP_ERR_NOERROR;
}
snmp_err_t
snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
/* because our only instance is .0 we can only return a next instance if no instance oid is passed */
if (instance->instance_oid.len == 0) {
instance->instance_oid.len = 1;
instance->instance_oid.id[0] = 0;
return snmp_scalar_get_instance(root_oid, root_oid_len, instance);
}
return SNMP_ERR_NOSUCHINSTANCE;
}
snmp_err_t
snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
if ((instance->instance_oid.len == 2) && (instance->instance_oid.id[1] == 0)) {
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = array_node->array_nodes;
u32_t i = 0;
while (i < array_node->array_node_count) {
if (array_node_def->oid == instance->instance_oid.id[0]) {
break;
}
array_node_def++;
i++;
}
if (i < array_node->array_node_count) {
instance->access = array_node_def->access;
instance->asn1_type = array_node_def->asn1_type;
instance->get_value = snmp_scalar_array_get_value;
instance->set_test = snmp_scalar_array_set_test;
instance->set_value = snmp_scalar_array_set_value;
instance->reference.const_ptr = array_node_def;
return SNMP_ERR_NOERROR;
}
}
return SNMP_ERR_NOSUCHINSTANCE;
}
snmp_err_t
snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = array_node->array_nodes;
const struct snmp_scalar_array_node_def* result = NULL;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
if ((instance->instance_oid.len == 0) && (array_node->array_node_count > 0)) {
/* return node with lowest OID */
u16_t i = 0;
result = array_node_def;
array_node_def++;
for (i = 1; i < array_node->array_node_count; i++) {
if (array_node_def->oid < result->oid) {
result = array_node_def;
}
array_node_def++;
}
} else if (instance->instance_oid.len >= 1) {
if (instance->instance_oid.len == 1) {
/* if we have the requested OID we return its instance, otherwise we search for the next available */
u16_t i = 0;
while (i < array_node->array_node_count) {
if (array_node_def->oid == instance->instance_oid.id[0]) {
result = array_node_def;
break;
}
array_node_def++;
i++;
}
}
if (result == NULL) {
u32_t oid_dist = 0xFFFFFFFFUL;
u16_t i = 0;
array_node_def = array_node->array_nodes; /* may be already at the end when if case before was executed without result -> reinitialize to start */
while (i < array_node->array_node_count) {
if ((array_node_def->oid > instance->instance_oid.id[0]) &&
((u32_t)(array_node_def->oid - instance->instance_oid.id[0]) < oid_dist)) {
result = array_node_def;
oid_dist = array_node_def->oid - instance->instance_oid.id[0];
}
array_node_def++;
i++;
}
}
}
if (result == NULL) {
/* nothing to return */
return SNMP_ERR_NOSUCHINSTANCE;
}
instance->instance_oid.len = 2;
instance->instance_oid.id[0] = result->oid;
instance->instance_oid.id[1] = 0;
instance->access = result->access;
instance->asn1_type = result->asn1_type;
instance->get_value = snmp_scalar_array_get_value;
instance->set_test = snmp_scalar_array_set_test;
instance->set_value = snmp_scalar_array_set_value;
instance->reference.const_ptr = result;
return SNMP_ERR_NOERROR;
}
static s16_t
snmp_scalar_array_get_value(struct snmp_node_instance* instance, void* value)
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
return array_node->get_value(array_node_def, value);
}
static snmp_err_t
snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value)
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
return array_node->set_test(array_node_def, value_len, value);
}
static snmp_err_t
snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value)
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
return array_node->set_value(array_node_def, value_len, value);
}
#endif /* LWIP_SNMP */

View File

@@ -1,343 +0,0 @@
/**
* @file
* SNMP table support 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: Martin Hentschel <info@cl-soft.de>
*
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_table.h"
#include <string.h>
snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE;
const struct snmp_table_node* table_node = (const struct snmp_table_node*)(const void*)instance->node;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* check min. length (fixed row entry definition, column, row instance oid with at least one entry */
/* fixed row entry always has oid 1 */
if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) {
/* search column */
const struct snmp_table_col_def* col_def = table_node->columns;
u16_t i = table_node->column_count;
while (i > 0) {
if (col_def->index == instance->instance_oid.id[1]) {
break;
}
col_def++;
i--;
}
if (i > 0) {
/* everything may be overwritten by get_cell_instance_method() in order to implement special handling for single columns/cells */
instance->asn1_type = col_def->asn1_type;
instance->access = col_def->access;
instance->get_value = table_node->get_value;
instance->set_test = table_node->set_test;
instance->set_value = table_node->set_value;
ret = table_node->get_cell_instance(
&(instance->instance_oid.id[1]),
&(instance->instance_oid.id[2]),
instance->instance_oid.len-2,
instance);
}
}
return ret;
}
snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
const struct snmp_table_node* table_node = (const struct snmp_table_node*)(const void*)instance->node;
const struct snmp_table_col_def* col_def;
struct snmp_obj_id row_oid;
u32_t column = 0;
snmp_err_t result;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* check that first part of id is 0 or 1, referencing fixed row entry */
if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) {
return SNMP_ERR_NOSUCHINSTANCE;
}
if (instance->instance_oid.len > 1) {
column = instance->instance_oid.id[1];
}
if (instance->instance_oid.len > 2) {
snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2);
} else {
row_oid.len = 0;
}
instance->get_value = table_node->get_value;
instance->set_test = table_node->set_test;
instance->set_value = table_node->set_value;
/* resolve column and value */
do {
u16_t i;
const struct snmp_table_col_def* next_col_def = NULL;
col_def = table_node->columns;
for (i = 0; i < table_node->column_count; i++) {
if (col_def->index == column) {
next_col_def = col_def;
break;
} else if ((col_def->index > column) && ((next_col_def == NULL) || (col_def->index < next_col_def->index))) {
next_col_def = col_def;
}
col_def++;
}
if (next_col_def == NULL) {
/* no further column found */
return SNMP_ERR_NOSUCHINSTANCE;
}
instance->asn1_type = next_col_def->asn1_type;
instance->access = next_col_def->access;
result = table_node->get_next_cell_instance(
&next_col_def->index,
&row_oid,
instance);
if (result == SNMP_ERR_NOERROR) {
col_def = next_col_def;
break;
}
row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */
column = next_col_def->index + 1;
} while (1);
/* build resulting oid */
instance->instance_oid.len = 2;
instance->instance_oid.id[0] = 1;
instance->instance_oid.id[1] = col_def->index;
snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len);
return SNMP_ERR_NOERROR;
}
snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE;
const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)(const void*)instance->node;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* check min. length (fixed row entry definition, column, row instance oid with at least one entry */
/* fixed row entry always has oid 1 */
if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) {
ret = table_node->get_cell_value(
&(instance->instance_oid.id[1]),
&(instance->instance_oid.id[2]),
instance->instance_oid.len-2,
&instance->reference,
&instance->reference_len);
if (ret == SNMP_ERR_NOERROR) {
/* search column */
const struct snmp_table_simple_col_def* col_def = table_node->columns;
u32_t i = table_node->column_count;
while (i > 0) {
if (col_def->index == instance->instance_oid.id[1]) {
break;
}
col_def++;
i--;
}
if (i > 0) {
instance->asn1_type = col_def->asn1_type;
instance->access = SNMP_NODE_INSTANCE_READ_ONLY;
instance->set_test = NULL;
instance->set_value = NULL;
switch (col_def->data_type) {
case SNMP_VARIANT_VALUE_TYPE_U32:
instance->get_value = snmp_table_extract_value_from_u32ref;
break;
case SNMP_VARIANT_VALUE_TYPE_S32:
instance->get_value = snmp_table_extract_value_from_s32ref;
break;
case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */
case SNMP_VARIANT_VALUE_TYPE_CONST_PTR:
instance->get_value = snmp_table_extract_value_from_refconstptr;
break;
default:
LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type));
return SNMP_ERR_GENERROR;
}
ret = SNMP_ERR_NOERROR;
} else {
ret = SNMP_ERR_NOSUCHINSTANCE;
}
}
}
return ret;
}
snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)(const void*)instance->node;
const struct snmp_table_simple_col_def* col_def;
struct snmp_obj_id row_oid;
u32_t column = 0;
snmp_err_t result;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* check that first part of id is 0 or 1, referencing fixed row entry */
if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) {
return SNMP_ERR_NOSUCHINSTANCE;
}
if (instance->instance_oid.len > 1) {
column = instance->instance_oid.id[1];
}
if (instance->instance_oid.len > 2) {
snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2);
} else {
row_oid.len = 0;
}
/* resolve column and value */
do {
u32_t i;
const struct snmp_table_simple_col_def* next_col_def = NULL;
col_def = table_node->columns;
for (i = 0; i < table_node->column_count; i++) {
if (col_def->index == column) {
next_col_def = col_def;
break;
} else if ((col_def->index > column) && ((next_col_def == NULL) ||
(col_def->index < next_col_def->index))) {
next_col_def = col_def;
}
col_def++;
}
if (next_col_def == NULL) {
/* no further column found */
return SNMP_ERR_NOSUCHINSTANCE;
}
result = table_node->get_next_cell_instance_and_value(
&next_col_def->index,
&row_oid,
&instance->reference,
&instance->reference_len);
if (result == SNMP_ERR_NOERROR) {
col_def = next_col_def;
break;
}
row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */
column = next_col_def->index + 1;
}
while (1);
instance->asn1_type = col_def->asn1_type;
instance->access = SNMP_NODE_INSTANCE_READ_ONLY;
instance->set_test = NULL;
instance->set_value = NULL;
switch (col_def->data_type) {
case SNMP_VARIANT_VALUE_TYPE_U32:
instance->get_value = snmp_table_extract_value_from_u32ref;
break;
case SNMP_VARIANT_VALUE_TYPE_S32:
instance->get_value = snmp_table_extract_value_from_s32ref;
break;
case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */
case SNMP_VARIANT_VALUE_TYPE_CONST_PTR:
instance->get_value = snmp_table_extract_value_from_refconstptr;
break;
default:
LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type));
return SNMP_ERR_GENERROR;
}
/* build resulting oid */
instance->instance_oid.len = 2;
instance->instance_oid.id[0] = 1;
instance->instance_oid.id[1] = col_def->index;
snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len);
return SNMP_ERR_NOERROR;
}
s16_t
snmp_table_extract_value_from_s32ref(struct snmp_node_instance* instance, void* value)
{
s32_t *dst = (s32_t*)value;
*dst = instance->reference.s32;
return sizeof(*dst);
}
s16_t
snmp_table_extract_value_from_u32ref(struct snmp_node_instance* instance, void* value)
{
u32_t *dst = (u32_t*)value;
*dst = instance->reference.u32;
return sizeof(*dst);
}
s16_t
snmp_table_extract_value_from_refconstptr(struct snmp_node_instance* instance, void* value)
{
MEMCPY(value, instance->reference.const_ptr, instance->reference_len);
return (u16_t)instance->reference_len;
}
#endif /* LWIP_SNMP */

View File

@@ -1,219 +0,0 @@
/**
* @file
* SNMP thread synchronization 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.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP && (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_threadsync.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/sys.h"
#include <string.h>
static void
call_synced_function(struct threadsync_data *call_data, snmp_threadsync_called_fn fn)
{
sys_mutex_lock(&call_data->threadsync_node->instance->sem_usage_mutex);
call_data->threadsync_node->instance->sync_fn(fn, call_data);
sys_sem_wait(&call_data->threadsync_node->instance->sem);
sys_mutex_unlock(&call_data->threadsync_node->instance->sem_usage_mutex);
}
static void
threadsync_get_value_synced(void *ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
call_data->retval.s16 = call_data->proxy_instance.get_value(&call_data->proxy_instance, call_data->arg1.value);
sys_sem_signal(&call_data->threadsync_node->instance->sem);
}
static s16_t
threadsync_get_value(struct snmp_node_instance* instance, void* value)
{
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
call_data->arg1.value = value;
call_synced_function(call_data, threadsync_get_value_synced);
return call_data->retval.s16;
}
static void
threadsync_set_test_synced(void *ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
call_data->retval.err = call_data->proxy_instance.set_test(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
sys_sem_signal(&call_data->threadsync_node->instance->sem);
}
static snmp_err_t
threadsync_set_test(struct snmp_node_instance* instance, u16_t len, void *value)
{
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
call_data->arg1.value = value;
call_data->arg2.len = len;
call_synced_function(call_data, threadsync_set_test_synced);
return call_data->retval.err;
}
static void
threadsync_set_value_synced(void *ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
call_data->retval.err = call_data->proxy_instance.set_value(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
sys_sem_signal(&call_data->threadsync_node->instance->sem);
}
static snmp_err_t
threadsync_set_value(struct snmp_node_instance* instance, u16_t len, void *value)
{
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
call_data->arg1.value = value;
call_data->arg2.len = len;
call_synced_function(call_data, threadsync_set_value_synced);
return call_data->retval.err;
}
static void
threadsync_release_instance_synced(void* ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
call_data->proxy_instance.release_instance(&call_data->proxy_instance);
sys_sem_signal(&call_data->threadsync_node->instance->sem);
}
static void
threadsync_release_instance(struct snmp_node_instance *instance)
{
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
if (call_data->proxy_instance.release_instance != NULL) {
call_synced_function(call_data, threadsync_release_instance_synced);
}
}
static void
get_instance_synced(void* ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node*)(const void*)call_data->proxy_instance.node;
call_data->retval.err = leaf->get_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance);
sys_sem_signal(&call_data->threadsync_node->instance->sem);
}
static void
get_next_instance_synced(void* ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node*)(const void*)call_data->proxy_instance.node;
call_data->retval.err = leaf->get_next_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance);
sys_sem_signal(&call_data->threadsync_node->instance->sem);
}
static snmp_err_t
do_sync(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance, snmp_threadsync_called_fn fn)
{
const struct snmp_threadsync_node *threadsync_node = (const struct snmp_threadsync_node*)(const void*)instance->node;
struct threadsync_data *call_data = &threadsync_node->instance->data;
if (threadsync_node->node.node.oid != threadsync_node->target->node.oid) {
LWIP_DEBUGF(SNMP_DEBUG, ("Sync node OID does not match target node OID"));
return SNMP_ERR_NOSUCHINSTANCE;
}
memset(&call_data->proxy_instance, 0, sizeof(call_data->proxy_instance));
instance->reference.ptr = call_data;
snmp_oid_assign(&call_data->proxy_instance.instance_oid, instance->instance_oid.id, instance->instance_oid.len);
call_data->proxy_instance.node = &threadsync_node->target->node;
call_data->threadsync_node = threadsync_node;
call_data->arg1.root_oid = root_oid;
call_data->arg2.root_oid_len = root_oid_len;
call_synced_function(call_data, fn);
if (call_data->retval.err == SNMP_ERR_NOERROR) {
instance->access = call_data->proxy_instance.access;
instance->asn1_type = call_data->proxy_instance.asn1_type;
instance->release_instance = threadsync_release_instance;
instance->get_value = (call_data->proxy_instance.get_value != NULL)? threadsync_get_value : NULL;
instance->set_value = (call_data->proxy_instance.set_value != NULL)? threadsync_set_value : NULL;
instance->set_test = (call_data->proxy_instance.set_test != NULL)? threadsync_set_test : NULL;
snmp_oid_assign(&instance->instance_oid, call_data->proxy_instance.instance_oid.id, call_data->proxy_instance.instance_oid.len);
}
return call_data->retval.err;
}
snmp_err_t
snmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
return do_sync(root_oid, root_oid_len, instance, get_instance_synced);
}
snmp_err_t
snmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
return do_sync(root_oid, root_oid_len, instance, get_next_instance_synced);
}
/** Initializes thread synchronization instance */
void snmp_threadsync_init(struct snmp_threadsync_instance *instance, snmp_threadsync_synchronizer_fn sync_fn)
{
err_t err = sys_mutex_new(&instance->sem_usage_mutex);
LWIP_ASSERT("Failed to set up mutex", err == ERR_OK);
err = sys_sem_new(&instance->sem, 0);
LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("Failed to set up semaphore", err == ERR_OK);
instance->sync_fn = sync_fn;
}
#endif /* LWIP_SNMP */

View File

@@ -1,445 +0,0 @@
/**
* @file
* SNMPv1 traps 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: Martin Hentschel
* Christiaan Simons <christiaan.simons@axon.tv>
*
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include <string.h>
#include "lwip/snmp.h"
#include "lwip/sys.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "snmp_msg.h"
#include "snmp_asn1.h"
#include "snmp_core_priv.h"
struct snmp_msg_trap
{
/* source enterprise ID (sysObjectID) */
const struct snmp_obj_id *enterprise;
/* source IP address, raw network order format */
ip_addr_t sip;
/* generic trap code */
u32_t gen_trap;
/* specific trap code */
u32_t spc_trap;
/* timestamp */
u32_t ts;
/* snmp_version */
u32_t snmp_version;
/* output trap lengths used in ASN encoding */
/* encoding pdu length */
u16_t pdulen;
/* encoding community length */
u16_t comlen;
/* encoding sequence length */
u16_t seqlen;
/* encoding varbinds sequence length */
u16_t vbseqlen;
};
static u16_t snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds);
static u16_t snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len);
static void snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream);
static void snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds);
/** Agent community string for sending traps */
extern const char *snmp_community_trap;
void* snmp_traps_handle;
struct snmp_trap_dst
{
/* destination IP address in network order */
ip_addr_t dip;
/* set to 0 when disabled, >0 when enabled */
u8_t enable;
};
static struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];
static u8_t snmp_auth_traps_enabled = 0;
/**
* @ingroup snmp_traps
* Sets enable switch for this trap destination.
* @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
* @param enable switch if 0 destination is disabled >0 enabled.
*/
void
snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)
{
if (dst_idx < SNMP_TRAP_DESTINATIONS) {
trap_dst[dst_idx].enable = enable;
}
}
/**
* @ingroup snmp_traps
* Sets IPv4 address for this trap destination.
* @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
* @param dst IPv4 address in host order.
*/
void
snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst)
{
if (dst_idx < SNMP_TRAP_DESTINATIONS) {
ip_addr_set(&trap_dst[dst_idx].dip, dst);
}
}
/**
* @ingroup snmp_traps
* Enable/disable authentication traps
*/
void
snmp_set_auth_traps_enabled(u8_t enable)
{
snmp_auth_traps_enabled = enable;
}
/**
* @ingroup snmp_traps
* Get authentication traps enabled state
*/
u8_t
snmp_get_auth_traps_enabled(void)
{
return snmp_auth_traps_enabled;
}
/**
* @ingroup snmp_traps
* Sends a generic or enterprise specific trap message.
*
* @param eoid points to enterprise object identifier
* @param generic_trap is the trap code
* @param specific_trap used for enterprise traps when generic_trap == 6
* @param varbinds linked list of varbinds to be sent
* @return ERR_OK when success, ERR_MEM if we're out of memory
*
* @note the use of the enterprise identifier field
* is per RFC1215.
* Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps
* and .iso.org.dod.internet.private.enterprises.yourenterprise
* (sysObjectID) for specific traps.
*/
err_t
snmp_send_trap(const struct snmp_obj_id* eoid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds)
{
struct snmp_msg_trap trap_msg;
struct snmp_trap_dst *td;
struct pbuf *p;
u16_t i, tot_len;
err_t err = ERR_OK;
trap_msg.snmp_version = 0;
for (i = 0, td = &trap_dst[0]; i < SNMP_TRAP_DESTINATIONS; i++, td++) {
if ((td->enable != 0) && !ip_addr_isany(&td->dip)) {
/* lookup current source address for this dst */
if (snmp_get_local_ip_for_dst(snmp_traps_handle, &td->dip, &trap_msg.sip)) {
if (eoid == NULL) {
trap_msg.enterprise = snmp_get_device_enterprise_oid();
} else {
trap_msg.enterprise = eoid;
}
trap_msg.gen_trap = generic_trap;
if (generic_trap == SNMP_GENTRAP_ENTERPRISE_SPECIFIC) {
trap_msg.spc_trap = specific_trap;
} else {
trap_msg.spc_trap = 0;
}
MIB2_COPY_SYSUPTIME_TO(&trap_msg.ts);
/* pass 0, calculate length fields */
tot_len = snmp_trap_varbind_sum(&trap_msg, varbinds);
tot_len = snmp_trap_header_sum(&trap_msg, tot_len);
/* allocate pbuf(s) */
p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM);
if (p != NULL) {
struct snmp_pbuf_stream pbuf_stream;
snmp_pbuf_stream_init(&pbuf_stream, p, 0, tot_len);
/* pass 1, encode packet ino the pbuf(s) */
snmp_trap_header_enc(&trap_msg, &pbuf_stream);
snmp_trap_varbind_enc(&trap_msg, &pbuf_stream, varbinds);
snmp_stats.outtraps++;
snmp_stats.outpkts++;
/** send to the TRAP destination */
snmp_sendto(snmp_traps_handle, p, &td->dip, SNMP_TRAP_PORT);
pbuf_free(p);
} else {
err = ERR_MEM;
}
} else {
/* routing error */
err = ERR_RTE;
}
}
}
return err;
}
/**
* @ingroup snmp_traps
* Send generic SNMP trap
*/
err_t
snmp_send_trap_generic(s32_t generic_trap)
{
static const struct snmp_obj_id oid = { 7, { 1, 3, 6, 1, 2, 1, 11 } };
return snmp_send_trap(&oid, generic_trap, 0, NULL);
}
/**
* @ingroup snmp_traps
* Send specific SNMP trap with variable bindings
*/
err_t
snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds)
{
return snmp_send_trap(NULL, SNMP_GENTRAP_ENTERPRISE_SPECIFIC, specific_trap, varbinds);
}
/**
* @ingroup snmp_traps
* Send coldstart trap
*/
void
snmp_coldstart_trap(void)
{
snmp_send_trap_generic(SNMP_GENTRAP_COLDSTART);
}
/**
* @ingroup snmp_traps
* Send authentication failure trap (used internally by agent)
*/
void
snmp_authfail_trap(void)
{
if (snmp_auth_traps_enabled != 0) {
snmp_send_trap_generic(SNMP_GENTRAP_AUTH_FAILURE);
}
}
static u16_t
snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds)
{
struct snmp_varbind *varbind;
u16_t tot_len;
u8_t tot_len_len;
tot_len = 0;
varbind = varbinds;
while (varbind != NULL) {
struct snmp_varbind_len len;
if (snmp_varbind_length(varbind, &len) == ERR_OK) {
tot_len += 1 + len.vb_len_len + len.vb_value_len;
}
varbind = varbind->next;
}
trap->vbseqlen = tot_len;
snmp_asn1_enc_length_cnt(trap->vbseqlen, &tot_len_len);
tot_len += 1 + tot_len_len;
return tot_len;
}
/**
* Sums trap header field lengths from tail to head and
* returns trap_header_lengths for second encoding pass.
*
* @param trap Trap message
* @param vb_len varbind-list length
* @return the required length for encoding the trap header
*/
static u16_t
snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len)
{
u16_t tot_len;
u16_t len;
u8_t lenlen;
tot_len = vb_len;
snmp_asn1_enc_u32t_cnt(trap->ts, &len);
snmp_asn1_enc_length_cnt(len, &lenlen);
tot_len += 1 + len + lenlen;
snmp_asn1_enc_s32t_cnt(trap->spc_trap, &len);
snmp_asn1_enc_length_cnt(len, &lenlen);
tot_len += 1 + len + lenlen;
snmp_asn1_enc_s32t_cnt(trap->gen_trap, &len);
snmp_asn1_enc_length_cnt(len, &lenlen);
tot_len += 1 + len + lenlen;
if (IP_IS_V6_VAL(trap->sip)) {
#if LWIP_IPV6
len = sizeof(ip_2_ip6(&trap->sip)->addr);
#endif
} else {
#if LWIP_IPV4
len = sizeof(ip_2_ip4(&trap->sip)->addr);
#endif
}
snmp_asn1_enc_length_cnt(len, &lenlen);
tot_len += 1 + len + lenlen;
snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &len);
snmp_asn1_enc_length_cnt(len, &lenlen);
tot_len += 1 + len + lenlen;
trap->pdulen = tot_len;
snmp_asn1_enc_length_cnt(trap->pdulen, &lenlen);
tot_len += 1 + lenlen;
trap->comlen = (u16_t)LWIP_MIN(strlen(snmp_community_trap), 0xFFFF);
snmp_asn1_enc_length_cnt(trap->comlen, &lenlen);
tot_len += 1 + lenlen + trap->comlen;
snmp_asn1_enc_s32t_cnt(trap->snmp_version, &len);
snmp_asn1_enc_length_cnt(len, &lenlen);
tot_len += 1 + len + lenlen;
trap->seqlen = tot_len;
snmp_asn1_enc_length_cnt(trap->seqlen, &lenlen);
tot_len += 1 + lenlen;
return tot_len;
}
static void
snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds)
{
struct snmp_asn1_tlv tlv;
struct snmp_varbind *varbind;
varbind = varbinds;
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->vbseqlen);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
while (varbind != NULL) {
snmp_append_outbound_varbind(pbuf_stream, varbind);
varbind = varbind->next;
}
}
/**
* Encodes trap header from head to tail.
*/
static void
snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream)
{
struct snmp_asn1_tlv tlv;
/* 'Message' sequence */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->seqlen);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
/* version */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
snmp_asn1_enc_s32t_cnt(trap->snmp_version, &tlv.value_len);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->snmp_version);
/* community */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, trap->comlen);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)snmp_community_trap, trap->comlen);
/* 'PDU' sequence */
SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_TRAP), 0, trap->pdulen);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
/* object ID */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, 0, 0);
snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &tlv.value_len);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_oid(pbuf_stream, trap->enterprise->id, trap->enterprise->len);
/* IP addr */
if (IP_IS_V6_VAL(trap->sip)) {
#if LWIP_IPV6
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip6(&trap->sip)->addr));
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip6(&trap->sip)->addr, sizeof(ip_2_ip6(&trap->sip)->addr));
#endif
} else {
#if LWIP_IPV4
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip4(&trap->sip)->addr));
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip4(&trap->sip)->addr, sizeof(ip_2_ip4(&trap->sip)->addr));
#endif
}
/* trap length */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
snmp_asn1_enc_s32t_cnt(trap->gen_trap, &tlv.value_len);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->gen_trap);
/* specific trap */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
snmp_asn1_enc_s32t_cnt(trap->spc_trap, &tlv.value_len);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->spc_trap);
/* timestamp */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_TIMETICKS, 0, 0);
snmp_asn1_enc_s32t_cnt(trap->ts, &tlv.value_len);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->ts);
}
#endif /* LWIP_SNMP */

View File

@@ -1,136 +0,0 @@
/**
* @file
* Additional SNMPv3 functionality RFC3414 and RFC3826.
*/
/*
* Copyright (c) 2016 Elias Oenal.
* 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.
*
* Author: Elias Oenal <lwip@eliasoenal.com>
*/
#include "snmpv3_priv.h"
#include "lwip/apps/snmpv3.h"
#include "lwip/sys.h"
#include <string.h>
#if LWIP_SNMP && LWIP_SNMP_V3
#ifdef LWIP_SNMPV3_INCLUDE_ENGINE
#include LWIP_SNMPV3_INCLUDE_ENGINE
#endif
#define SNMP_MAX_TIME_BOOT 2147483647UL
/** Call this if engine has been changed. Has to reset boots, see below */
void
snmpv3_engine_id_changed(void)
{
snmpv3_set_engine_boots(0);
}
/** According to RFC3414 2.2.2.
*
* The number of times that the SNMP engine has
* (re-)initialized itself since snmpEngineID
* was last configured.
*/
u32_t
snmpv3_get_engine_boots_internal(void)
{
if (snmpv3_get_engine_boots() == 0 ||
snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT) {
return snmpv3_get_engine_boots();
}
snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT);
return snmpv3_get_engine_boots();
}
/** RFC3414 2.2.2.
*
* Once the timer reaches 2147483647 it gets reset to zero and the
* engine boot ups get incremented.
*/
u32_t
snmpv3_get_engine_time_internal(void)
{
if (snmpv3_get_engine_time() >= SNMP_MAX_TIME_BOOT) {
snmpv3_reset_engine_time();
if (snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT - 1) {
snmpv3_set_engine_boots(snmpv3_get_engine_boots() + 1);
} else {
snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT);
}
}
return snmpv3_get_engine_time();
}
#if LWIP_SNMP_V3_CRYPTO
/* This function ignores the byte order suggestion in RFC3414
* since it simply doesn't influence the effectiveness of an IV.
*
* Implementing RFC3826 priv param algorithm if LWIP_RAND is available.
*
* @todo: This is a potential thread safety issue.
*/
err_t
snmpv3_build_priv_param(u8_t* priv_param)
{
#ifdef LWIP_RAND /* Based on RFC3826 */
static u8_t init;
static u32_t priv1, priv2;
/* Lazy initialisation */
if (init == 0) {
init = 1;
priv1 = LWIP_RAND();
priv2 = LWIP_RAND();
}
SMEMCPY(&priv_param[0], &priv1, sizeof(priv1));
SMEMCPY(&priv_param[4], &priv2, sizeof(priv2));
/* Emulate 64bit increment */
priv1++;
if (!priv1) { /* Overflow */
priv2++;
}
#else /* Based on RFC3414 */
static u32_t ctr;
u32_t boots = LWIP_SNMPV3_GET_ENGINE_BOOTS();
SMEMCPY(&priv_param[0], &boots, 4);
SMEMCPY(&priv_param[4], &ctr, 4);
ctr++;
#endif
return ERR_OK;
}
#endif /* LWIP_SNMP_V3_CRYPTO */
#endif

View File

@@ -1,145 +0,0 @@
/**
* @file
* Dummy SNMPv3 functions.
*/
/*
* Copyright (c) 2016 Elias Oenal.
* 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.
*
* Author: Elias Oenal <lwip@eliasoenal.com>
* Dirk Ziegelmeier <dirk@ziegelmeier.net>
*/
#include "lwip/apps/snmpv3.h"
#include "snmpv3_priv.h"
#include <string.h>
#include "lwip/err.h"
#if LWIP_SNMP && LWIP_SNMP_V3
/**
* @param username is a pointer to a string.
* @param auth_algo is a pointer to u8_t. The implementation has to set this if user was found.
* @param auth_key is a pointer to a pointer to a string. Implementation has to set this if user was found.
* @param priv_algo is a pointer to u8_t. The implementation has to set this if user was found.
* @param priv_key is a pointer to a pointer to a string. Implementation has to set this if user was found.
*/
err_t
snmpv3_get_user(const char* username, u8_t *auth_algo, u8_t *auth_key, u8_t *priv_algo, u8_t *priv_key)
{
const char* engine_id;
u8_t engine_id_len;
if(strlen(username) == 0) {
return ERR_OK;
}
if(memcmp(username, "lwip", 4) != 0) {
return ERR_VAL;
}
snmpv3_get_engine_id(&engine_id, &engine_id_len);
if(auth_key != NULL) {
snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10,
(const u8_t*)engine_id, engine_id_len,
auth_key);
*auth_algo = SNMP_V3_AUTH_ALGO_SHA;
}
if(priv_key != NULL) {
snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10,
(const u8_t*)engine_id, engine_id_len,
priv_key);
*priv_algo = SNMP_V3_PRIV_ALGO_DES;
}
return ERR_OK;
}
/**
* Get engine ID from persistence
* @param id
* @param len
*/
void
snmpv3_get_engine_id(const char **id, u8_t *len)
{
*id = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02";
*len = 12;
}
/**
* Store engine ID in persistence
* @param id
* @param len
*/
err_t
snmpv3_set_engine_id(const char *id, u8_t len)
{
LWIP_UNUSED_ARG(id);
LWIP_UNUSED_ARG(len);
return ERR_OK;
}
/**
* Get engine boots from persistence. Must be increased on each boot.
* @return
*/
u32_t
snmpv3_get_engine_boots(void)
{
return 0;
}
/**
* Store engine boots in persistence
* @param boots
*/
void
snmpv3_set_engine_boots(u32_t boots)
{
LWIP_UNUSED_ARG(boots);
}
/**
* RFC3414 2.2.2.
* Once the timer reaches 2147483647 it gets reset to zero and the
* engine boot ups get incremented.
*/
u32_t
snmpv3_get_engine_time(void)
{
return 0;
}
/**
* Reset current engine time to 0
*/
void
snmpv3_reset_engine_time(void)
{
}
#endif /* LWIP_SNMP && LWIP_SNMP_V3 */

View File

@@ -1,331 +0,0 @@
/**
* @file
* SNMPv3 crypto/auth functions implemented for ARM mbedtls.
*/
/*
* Copyright (c) 2016 Elias Oenal and Dirk Ziegelmeier.
* 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.
*
* Author: Elias Oenal <lwip@eliasoenal.com>
* Dirk Ziegelmeier <dirk@ziegelmeier.net>
*/
#include "lwip/apps/snmpv3.h"
#include "snmpv3_priv.h"
#include "lwip/arch.h"
#include "snmp_msg.h"
#include "lwip/sys.h"
#include <string.h>
#if LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS
#include "mbedtls/md.h"
#include "mbedtls/cipher.h"
#include "mbedtls/md5.h"
#include "mbedtls/sha1.h"
err_t
snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length,
const u8_t* key, u8_t algo, u8_t* hmac_out)
{
u32_t i;
u8_t key_len;
const mbedtls_md_info_t *md_info;
mbedtls_md_context_t ctx;
struct snmp_pbuf_stream read_stream;
snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length);
if (algo == SNMP_V3_AUTH_ALGO_MD5) {
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
key_len = SNMP_V3_MD5_LEN;
} else if (algo == SNMP_V3_AUTH_ALGO_SHA) {
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
key_len = SNMP_V3_SHA_LEN;
} else {
return ERR_ARG;
}
mbedtls_md_init(&ctx);
if(mbedtls_md_setup(&ctx, md_info, 1) != 0) {
return ERR_ARG;
}
if (mbedtls_md_hmac_starts(&ctx, key, key_len) != 0) {
goto free_md;
}
for (i = 0; i < length; i++) {
u8_t byte;
if (snmp_pbuf_stream_read(&read_stream, &byte)) {
goto free_md;
}
if (mbedtls_md_hmac_update(&ctx, &byte, 1) != 0) {
goto free_md;
}
}
if (mbedtls_md_hmac_finish(&ctx, hmac_out) != 0) {
goto free_md;
}
mbedtls_md_free(&ctx);
return ERR_OK;
free_md:
mbedtls_md_free(&ctx);
return ERR_ARG;
}
#if LWIP_SNMP_V3_CRYPTO
err_t
snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length,
const u8_t* key, const u8_t* priv_param, const u32_t engine_boots,
const u32_t engine_time, u8_t algo, u8_t mode)
{
size_t i;
mbedtls_cipher_context_t ctx;
const mbedtls_cipher_info_t *cipher_info;
struct snmp_pbuf_stream read_stream;
struct snmp_pbuf_stream write_stream;
snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length);
snmp_pbuf_stream_init(&write_stream, stream->pbuf, stream->offset, stream->length);
mbedtls_cipher_init(&ctx);
if (algo == SNMP_V3_PRIV_ALGO_DES) {
u8_t iv_local[8];
u8_t out_bytes[8];
size_t out_len;
/* RFC 3414 mandates padding for DES */
if ((length & 0x07) != 0) {
return ERR_ARG;
}
cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_DES_CBC);
if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
return ERR_ARG;
}
if(mbedtls_cipher_set_padding_mode(&ctx, MBEDTLS_PADDING_NONE) != 0) {
return ERR_ARG;
}
if(mbedtls_cipher_setkey(&ctx, key, 8*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) {
goto error;
}
/* Prepare IV */
for (i = 0; i < LWIP_ARRAYSIZE(iv_local); i++) {
iv_local[i] = priv_param[i] ^ key[i + 8];
}
if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) {
goto error;
}
for (i = 0; i < length; i += 8) {
size_t j;
u8_t in_bytes[8];
out_len = LWIP_ARRAYSIZE(out_bytes) ;
for (j = 0; j < LWIP_ARRAYSIZE(in_bytes); j++) {
snmp_pbuf_stream_read(&read_stream, &in_bytes[j]);
}
if(mbedtls_cipher_update(&ctx, in_bytes, LWIP_ARRAYSIZE(in_bytes), out_bytes, &out_len) != 0) {
goto error;
}
snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len);
}
out_len = LWIP_ARRAYSIZE(out_bytes);
if(mbedtls_cipher_finish(&ctx, out_bytes, &out_len) != 0) {
goto error;
}
snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len);
} else if (algo == SNMP_V3_PRIV_ALGO_AES) {
u8_t iv_local[16];
cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CFB128);
if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
return ERR_ARG;
}
if(mbedtls_cipher_setkey(&ctx, key, 16*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) {
goto error;
}
/*
* IV is the big endian concatenation of boots,
* uptime and priv param - see RFC3826.
*/
iv_local[0 + 0] = (engine_boots >> 24) & 0xFF;
iv_local[0 + 1] = (engine_boots >> 16) & 0xFF;
iv_local[0 + 2] = (engine_boots >> 8) & 0xFF;
iv_local[0 + 3] = (engine_boots >> 0) & 0xFF;
iv_local[4 + 0] = (engine_time >> 24) & 0xFF;
iv_local[4 + 1] = (engine_time >> 16) & 0xFF;
iv_local[4 + 2] = (engine_time >> 8) & 0xFF;
iv_local[4 + 3] = (engine_time >> 0) & 0xFF;
SMEMCPY(iv_local + 8, priv_param, 8);
if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) {
goto error;
}
for (i = 0; i < length; i++) {
u8_t in_byte;
u8_t out_byte;
size_t out_len = sizeof(out_byte);
snmp_pbuf_stream_read(&read_stream, &in_byte);
if(mbedtls_cipher_update(&ctx, &in_byte, sizeof(in_byte), &out_byte, &out_len) != 0) {
goto error;
}
snmp_pbuf_stream_write(&write_stream, out_byte);
}
} else {
return ERR_ARG;
}
mbedtls_cipher_free(&ctx);
return ERR_OK;
error:
mbedtls_cipher_free(&ctx);
return ERR_OK;
}
#endif /* LWIP_SNMP_V3_CRYPTO */
/* A.2.1. Password to Key Sample Code for MD5 */
void
snmpv3_password_to_key_md5(
const u8_t *password, /* IN */
u8_t passwordlen, /* IN */
const u8_t *engineID, /* IN - pointer to snmpEngineID */
u8_t engineLength,/* IN - length of snmpEngineID */
u8_t *key) /* OUT - pointer to caller 16-octet buffer */
{
mbedtls_md5_context MD;
u8_t *cp, password_buf[64];
u32_t password_index = 0;
u8_t i;
u32_t count = 0;
mbedtls_md5_init(&MD); /* initialize MD5 */
mbedtls_md5_starts(&MD);
/**********************************************/
/* Use while loop until we've done 1 Megabyte */
/**********************************************/
while (count < 1048576) {
cp = password_buf;
for (i = 0; i < 64; i++) {
/*************************************************/
/* Take the next octet of the password, wrapping */
/* to the beginning of the password as necessary.*/
/*************************************************/
*cp++ = password[password_index++ % passwordlen];
}
mbedtls_md5_update(&MD, password_buf, 64);
count += 64;
}
mbedtls_md5_finish(&MD, key); /* tell MD5 we're done */
/*****************************************************/
/* Now localize the key with the engineID and pass */
/* through MD5 to produce final key */
/* May want to ensure that engineLength <= 32, */
/* otherwise need to use a buffer larger than 64 */
/*****************************************************/
SMEMCPY(password_buf, key, 16);
MEMCPY(password_buf + 16, engineID, engineLength);
SMEMCPY(password_buf + 16 + engineLength, key, 16);
mbedtls_md5_starts(&MD);
mbedtls_md5_update(&MD, password_buf, 32 + engineLength);
mbedtls_md5_finish(&MD, key);
mbedtls_md5_free(&MD);
return;
}
/* A.2.2. Password to Key Sample Code for SHA */
void
snmpv3_password_to_key_sha(
const u8_t *password, /* IN */
u8_t passwordlen, /* IN */
const u8_t *engineID, /* IN - pointer to snmpEngineID */
u8_t engineLength,/* IN - length of snmpEngineID */
u8_t *key) /* OUT - pointer to caller 20-octet buffer */
{
mbedtls_sha1_context SH;
u8_t *cp, password_buf[72];
u32_t password_index = 0;
u8_t i;
u32_t count = 0;
mbedtls_sha1_init(&SH); /* initialize SHA */
mbedtls_sha1_starts(&SH);
/**********************************************/
/* Use while loop until we've done 1 Megabyte */
/**********************************************/
while (count < 1048576) {
cp = password_buf;
for (i = 0; i < 64; i++) {
/*************************************************/
/* Take the next octet of the password, wrapping */
/* to the beginning of the password as necessary.*/
/*************************************************/
*cp++ = password[password_index++ % passwordlen];
}
mbedtls_sha1_update(&SH, password_buf, 64);
count += 64;
}
mbedtls_sha1_finish(&SH, key); /* tell SHA we're done */
/*****************************************************/
/* Now localize the key with the engineID and pass */
/* through SHA to produce final key */
/* May want to ensure that engineLength <= 32, */
/* otherwise need to use a buffer larger than 72 */
/*****************************************************/
SMEMCPY(password_buf, key, 20);
MEMCPY(password_buf + 20, engineID, engineLength);
SMEMCPY(password_buf + 20 + engineLength, key, 20);
mbedtls_sha1_starts(&SH);
mbedtls_sha1_update(&SH, password_buf, 40 + engineLength);
mbedtls_sha1_finish(&SH, key);
mbedtls_sha1_free(&SH);
return;
}
#endif /* LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS */

View File

@@ -1,66 +0,0 @@
/**
* @file
* Additional SNMPv3 functionality RFC3414 and RFC3826 (internal API, do not use in client code).
*/
/*
* Copyright (c) 2016 Elias Oenal.
* 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.
*
* Author: Elias Oenal <lwip@eliasoenal.com>
*/
#ifndef LWIP_HDR_APPS_SNMP_V3_PRIV_H
#define LWIP_HDR_APPS_SNMP_V3_PRIV_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP && LWIP_SNMP_V3
#include "snmp_pbuf_stream.h"
/* According to RFC 3411 */
#define SNMP_V3_MAX_ENGINE_ID_LENGTH 32
#define SNMP_V3_MAX_USER_LENGTH 32
#define SNMP_V3_MAX_AUTH_PARAM_LENGTH 12
#define SNMP_V3_MAX_PRIV_PARAM_LENGTH 8
#define SNMP_V3_AUTH_FLAG 0x01
#define SNMP_V3_PRIV_FLAG 0x02
#define SNMP_V3_MD5_LEN 16
#define SNMP_V3_SHA_LEN 20
u32_t snmpv3_get_engine_boots_internal(void);
u32_t snmpv3_get_engine_time_internal(void);
err_t snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key, u8_t algo, u8_t* hmac_out);
err_t snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key,
const u8_t* priv_param, const u32_t engine_boots, const u32_t engine_time, u8_t algo, u8_t mode);
err_t snmpv3_build_priv_param(u8_t* priv_param);
#endif
#endif /* LWIP_HDR_APPS_SNMP_V3_PRIV_H */

View File

@@ -1,727 +0,0 @@
/**
* @file
* SNTP client module
*/
/*
* Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt
* 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: Frédéric Bernon, Simon Goldschmidt
*/
/**
* @defgroup sntp SNTP
* @ingroup apps
*
* This is simple "SNTP" client for the lwIP raw API.
* It is a minimal implementation of SNTPv4 as specified in RFC 4330.
*
* For a list of some public NTP servers, see this link :
* http://support.ntp.org/bin/view/Servers/NTPPoolServers
*
* @todo:
* - set/change servers at runtime
* - complete SNTP_CHECK_RESPONSE checks 3 and 4
*/
#include "lwip/apps/sntp.h"
#include "lwip/opt.h"
#include "lwip/timeouts.h"
#include "lwip/udp.h"
#include "lwip/dns.h"
#include "lwip/ip_addr.h"
#include "lwip/pbuf.h"
#include "lwip/dhcp.h"
#include <string.h>
#include <time.h>
#if LWIP_UDP
/* Handle support for more than one server via SNTP_MAX_SERVERS */
#if SNTP_MAX_SERVERS > 1
#define SNTP_SUPPORT_MULTIPLE_SERVERS 1
#else /* NTP_MAX_SERVERS > 1 */
#define SNTP_SUPPORT_MULTIPLE_SERVERS 0
#endif /* NTP_MAX_SERVERS > 1 */
#if (SNTP_UPDATE_DELAY < 15000) && !defined(SNTP_SUPPRESS_DELAY_CHECK)
#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!"
#endif
/* Configure behaviour depending on microsecond or second precision */
#ifdef SNTP_SET_SYSTEM_TIME_US
#define SNTP_CALC_TIME_US 1
#define SNTP_RECEIVE_TIME_SIZE 2
#else
#define SNTP_SET_SYSTEM_TIME_US(sec, us)
#define SNTP_CALC_TIME_US 0
#define SNTP_RECEIVE_TIME_SIZE 1
#endif
/* the various debug levels for this file */
#define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE)
#define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE)
#define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING)
#define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
#define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
#define SNTP_ERR_KOD 1
/* SNTP protocol defines */
#define SNTP_MSG_LEN 48
#define SNTP_OFFSET_LI_VN_MODE 0
#define SNTP_LI_MASK 0xC0
#define SNTP_LI_NO_WARNING 0x00
#define SNTP_LI_LAST_MINUTE_61_SEC 0x01
#define SNTP_LI_LAST_MINUTE_59_SEC 0x02
#define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */
#define SNTP_VERSION_MASK 0x38
#define SNTP_VERSION (4/* NTP Version 4*/<<3)
#define SNTP_MODE_MASK 0x07
#define SNTP_MODE_CLIENT 0x03
#define SNTP_MODE_SERVER 0x04
#define SNTP_MODE_BROADCAST 0x05
#define SNTP_OFFSET_STRATUM 1
#define SNTP_STRATUM_KOD 0x00
#define SNTP_OFFSET_ORIGINATE_TIME 24
#define SNTP_OFFSET_RECEIVE_TIME 32
#define SNTP_OFFSET_TRANSMIT_TIME 40
/* number of seconds between 1900 and 1970 (MSB=1)*/
#define DIFF_SEC_1900_1970 (2208988800UL)
/* number of seconds between 1970 and Feb 7, 2036 (6:28:16 UTC) (MSB=0) */
#define DIFF_SEC_1970_2036 (2085978496UL)
/**
* SNTP packet format (without optional fields)
* Timestamps are coded as 64 bits:
* - 32 bits seconds since Jan 01, 1970, 00:00
* - 32 bits seconds fraction (0-padded)
* For future use, if the MSB in the seconds part is set, seconds are based
* on Feb 07, 2036, 06:28:16.
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct sntp_msg {
PACK_STRUCT_FLD_8(u8_t li_vn_mode);
PACK_STRUCT_FLD_8(u8_t stratum);
PACK_STRUCT_FLD_8(u8_t poll);
PACK_STRUCT_FLD_8(u8_t precision);
PACK_STRUCT_FIELD(u32_t root_delay);
PACK_STRUCT_FIELD(u32_t root_dispersion);
PACK_STRUCT_FIELD(u32_t reference_identifier);
PACK_STRUCT_FIELD(u32_t reference_timestamp[2]);
PACK_STRUCT_FIELD(u32_t originate_timestamp[2]);
PACK_STRUCT_FIELD(u32_t receive_timestamp[2]);
PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* function prototypes */
static void sntp_request(void *arg);
/** The operating mode */
static u8_t sntp_opmode;
/** The UDP pcb used by the SNTP client */
static struct udp_pcb* sntp_pcb;
/** Names/Addresses of servers */
struct sntp_server {
#if SNTP_SERVER_DNS
char* name;
#endif /* SNTP_SERVER_DNS */
ip_addr_t addr;
};
static struct sntp_server sntp_servers[SNTP_MAX_SERVERS];
#if SNTP_GET_SERVERS_FROM_DHCP
static u8_t sntp_set_servers_from_dhcp;
#endif /* SNTP_GET_SERVERS_FROM_DHCP */
#if SNTP_SUPPORT_MULTIPLE_SERVERS
/** The currently used server (initialized to 0) */
static u8_t sntp_current_server;
#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
#define sntp_current_server 0
#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
#if SNTP_RETRY_TIMEOUT_EXP
#define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT
/** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */
static u32_t sntp_retry_timeout;
#else /* SNTP_RETRY_TIMEOUT_EXP */
#define SNTP_RESET_RETRY_TIMEOUT()
#define sntp_retry_timeout SNTP_RETRY_TIMEOUT
#endif /* SNTP_RETRY_TIMEOUT_EXP */
#if SNTP_CHECK_RESPONSE >= 1
/** Saves the last server address to compare with response */
static ip_addr_t sntp_last_server_address;
#endif /* SNTP_CHECK_RESPONSE >= 1 */
#if SNTP_CHECK_RESPONSE >= 2
/** Saves the last timestamp sent (which is sent back by the server)
* to compare against in response */
static u32_t sntp_last_timestamp_sent[2];
#endif /* SNTP_CHECK_RESPONSE >= 2 */
/**
* SNTP processing of received timestamp
*/
static void
sntp_process(u32_t *receive_timestamp)
{
/* convert SNTP time (1900-based) to unix GMT time (1970-based)
* if MSB is 0, SNTP time is 2036-based!
*/
u32_t rx_secs = lwip_ntohl(receive_timestamp[0]);
int is_1900_based = ((rx_secs & 0x80000000) != 0);
u32_t t = is_1900_based ? (rx_secs - DIFF_SEC_1900_1970) : (rx_secs + DIFF_SEC_1970_2036);
time_t tim = t;
#if SNTP_CALC_TIME_US
u32_t us = lwip_ntohl(receive_timestamp[1]) / 4295;
SNTP_SET_SYSTEM_TIME_US(t, us);
/* display local time from GMT time */
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&tim), us));
#else /* SNTP_CALC_TIME_US */
/* change system time and/or the update the RTC clock */
SNTP_SET_SYSTEM_TIME(t);
/* display local time from GMT time */
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim)));
#endif /* SNTP_CALC_TIME_US */
LWIP_UNUSED_ARG(tim);
}
/**
* Initialize request struct to be sent to server.
*/
static void
sntp_initialize_request(struct sntp_msg *req)
{
memset(req, 0, SNTP_MSG_LEN);
req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
#if SNTP_CHECK_RESPONSE >= 2
{
u32_t sntp_time_sec, sntp_time_us;
/* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */
SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us);
sntp_last_timestamp_sent[0] = lwip_htonl(sntp_time_sec + DIFF_SEC_1900_1970);
req->transmit_timestamp[0] = sntp_last_timestamp_sent[0];
/* we send/save us instead of fraction to be faster... */
sntp_last_timestamp_sent[1] = lwip_htonl(sntp_time_us);
req->transmit_timestamp[1] = sntp_last_timestamp_sent[1];
}
#endif /* SNTP_CHECK_RESPONSE >= 2 */
}
/**
* Retry: send a new request (and increase retry timeout).
*
* @param arg is unused (only necessary to conform to sys_timeout)
*/
static void
sntp_retry(void* arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n",
sntp_retry_timeout));
/* set up a timer to send a retry and increase the retry delay */
sys_timeout(sntp_retry_timeout, sntp_request, NULL);
#if SNTP_RETRY_TIMEOUT_EXP
{
u32_t new_retry_timeout;
/* increase the timeout for next retry */
new_retry_timeout = sntp_retry_timeout << 1;
/* limit to maximum timeout and prevent overflow */
if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) &&
(new_retry_timeout > sntp_retry_timeout)) {
sntp_retry_timeout = new_retry_timeout;
}
}
#endif /* SNTP_RETRY_TIMEOUT_EXP */
}
#if SNTP_SUPPORT_MULTIPLE_SERVERS
/**
* If Kiss-of-Death is received (or another packet parsing error),
* try the next server or retry the current server and increase the retry
* timeout if only one server is available.
* (implicitly, SNTP_MAX_SERVERS > 1)
*
* @param arg is unused (only necessary to conform to sys_timeout)
*/
static void
sntp_try_next_server(void* arg)
{
u8_t old_server, i;
LWIP_UNUSED_ARG(arg);
old_server = sntp_current_server;
for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) {
sntp_current_server++;
if (sntp_current_server >= SNTP_MAX_SERVERS) {
sntp_current_server = 0;
}
if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr)
#if SNTP_SERVER_DNS
|| (sntp_servers[sntp_current_server].name != NULL)
#endif
) {
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n",
(u16_t)sntp_current_server));
/* new server: reset retry timeout */
SNTP_RESET_RETRY_TIMEOUT();
/* instantly send a request to the next server */
sntp_request(NULL);
return;
}
}
/* no other valid server found */
sntp_current_server = old_server;
sntp_retry(NULL);
}
#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
/* Always retry on error if only one server is supported */
#define sntp_try_next_server sntp_retry
#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
/** UDP recv callback for the sntp pcb */
static void
sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
u8_t mode;
u8_t stratum;
u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE];
err_t err;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(pcb);
/* packet received: stop retry timeout */
sys_untimeout(sntp_try_next_server, NULL);
sys_untimeout(sntp_request, NULL);
err = ERR_ARG;
#if SNTP_CHECK_RESPONSE >= 1
/* check server address and port */
if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) &&
(port == SNTP_PORT))
#else /* SNTP_CHECK_RESPONSE >= 1 */
LWIP_UNUSED_ARG(addr);
LWIP_UNUSED_ARG(port);
#endif /* SNTP_CHECK_RESPONSE >= 1 */
{
/* process the response */
if (p->tot_len == SNTP_MSG_LEN) {
pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE);
mode &= SNTP_MODE_MASK;
/* if this is a SNTP response... */
if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) ||
((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) {
pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM);
if (stratum == SNTP_STRATUM_KOD) {
/* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
err = SNTP_ERR_KOD;
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n"));
} else {
#if SNTP_CHECK_RESPONSE >= 2
/* check originate_timetamp against sntp_last_timestamp_sent */
u32_t originate_timestamp[2];
pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME);
if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) ||
(originate_timestamp[1] != sntp_last_timestamp_sent[1]))
{
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n"));
} else
#endif /* SNTP_CHECK_RESPONSE >= 2 */
/* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */
{
/* correct answer */
err = ERR_OK;
pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_TRANSMIT_TIME);
}
}
} else {
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode));
/* wait for correct response */
err = ERR_TIMEOUT;
}
} else {
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len));
}
}
#if SNTP_CHECK_RESPONSE >= 1
else {
/* packet from wrong remote address or port, wait for correct response */
err = ERR_TIMEOUT;
}
#endif /* SNTP_CHECK_RESPONSE >= 1 */
pbuf_free(p);
if (err == ERR_OK) {
sntp_process(receive_timestamp);
/* Set up timeout for next request (only if poll response was received)*/
if (sntp_opmode == SNTP_OPMODE_POLL) {
/* Correct response, reset retry timeout */
SNTP_RESET_RETRY_TIMEOUT();
sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL);
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n",
(u32_t)SNTP_UPDATE_DELAY));
}
} else if (err != ERR_TIMEOUT) {
/* Errors are only processed in case of an explicit poll response */
if (sntp_opmode == SNTP_OPMODE_POLL) {
if (err == SNTP_ERR_KOD) {
/* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
sntp_try_next_server(NULL);
} else {
/* another error, try the same server again */
sntp_retry(NULL);
}
}
}
}
/** Actually send an sntp request to a server.
*
* @param server_addr resolved IP address of the SNTP server
*/
static void
sntp_send_request(const ip_addr_t *server_addr)
{
struct pbuf* p;
p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
if (p != NULL) {
struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload;
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n"));
/* initialize request message */
sntp_initialize_request(sntpmsg);
/* send request */
udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT);
/* free the pbuf after sending it */
pbuf_free(p);
/* set up receive timeout: try next server or retry on timeout */
sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
#if SNTP_CHECK_RESPONSE >= 1
/* save server address to verify it in sntp_recv */
ip_addr_set(&sntp_last_server_address, server_addr);
#endif /* SNTP_CHECK_RESPONSE >= 1 */
} else {
LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n",
(u32_t)SNTP_RETRY_TIMEOUT));
/* out of memory: set up a timer to send a retry */
sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL);
}
}
#if SNTP_SERVER_DNS
/**
* DNS found callback when using DNS names as server address.
*/
static void
sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
{
LWIP_UNUSED_ARG(hostname);
LWIP_UNUSED_ARG(arg);
if (ipaddr != NULL) {
/* Address resolved, send request */
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n"));
sntp_send_request(ipaddr);
} else {
/* DNS resolving failed -> try another server */
LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n"));
sntp_try_next_server(NULL);
}
}
#endif /* SNTP_SERVER_DNS */
/**
* Send out an sntp request.
*
* @param arg is unused (only necessary to conform to sys_timeout)
*/
static void
sntp_request(void *arg)
{
ip_addr_t sntp_server_address;
err_t err;
LWIP_UNUSED_ARG(arg);
/* initialize SNTP server address */
#if SNTP_SERVER_DNS
if (sntp_servers[sntp_current_server].name) {
/* always resolve the name and rely on dns-internal caching & timeout */
ip_addr_set_zero(&sntp_servers[sntp_current_server].addr);
err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address,
sntp_dns_found, NULL);
if (err == ERR_INPROGRESS) {
/* DNS request sent, wait for sntp_dns_found being called */
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n"));
return;
} else if (err == ERR_OK) {
sntp_servers[sntp_current_server].addr = sntp_server_address;
}
} else
#endif /* SNTP_SERVER_DNS */
{
sntp_server_address = sntp_servers[sntp_current_server].addr;
err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK;
}
if (err == ERR_OK) {
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n",
ipaddr_ntoa(&sntp_server_address)));
sntp_send_request(&sntp_server_address);
} else {
/* address conversion failed, try another server */
LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n"));
sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL);
}
}
/**
* @ingroup sntp
* Initialize this module.
* Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).
*/
void
sntp_init(void)
{
#ifdef SNTP_SERVER_ADDRESS
#if SNTP_SERVER_DNS
sntp_setservername(0, SNTP_SERVER_ADDRESS);
#else
#error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0
#endif
#endif /* SNTP_SERVER_ADDRESS */
if (sntp_pcb == NULL) {
sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
if (sntp_pcb != NULL) {
udp_recv(sntp_pcb, sntp_recv, NULL);
if (sntp_opmode == SNTP_OPMODE_POLL) {
SNTP_RESET_RETRY_TIMEOUT();
#if SNTP_STARTUP_DELAY
sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);
#else
sntp_request(NULL);
#endif
} else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) {
ip_set_option(sntp_pcb, SOF_BROADCAST);
udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT);
}
}
}
}
/**
* @ingroup sntp
* Stop this module.
*/
void
sntp_stop(void)
{
if (sntp_pcb != NULL) {
sys_untimeout(sntp_request, NULL);
sys_untimeout(sntp_try_next_server, NULL);
udp_remove(sntp_pcb);
sntp_pcb = NULL;
}
}
/**
* @ingroup sntp
* Get enabled state.
*/
u8_t sntp_enabled(void)
{
return (sntp_pcb != NULL)? 1 : 0;
}
/**
* @ingroup sntp
* Sets the operating mode.
* @param operating_mode one of the available operating modes
*/
void
sntp_setoperatingmode(u8_t operating_mode)
{
LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY);
LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL);
sntp_opmode = operating_mode;
}
/**
* @ingroup sntp
* Gets the operating mode.
*/
u8_t
sntp_getoperatingmode(void)
{
return sntp_opmode;
}
#if SNTP_GET_SERVERS_FROM_DHCP
/**
* Config SNTP server handling by IP address, name, or DHCP; clear table
* @param set_servers_from_dhcp enable or disable getting server addresses from dhcp
*/
void
sntp_servermode_dhcp(int set_servers_from_dhcp)
{
u8_t new_mode = set_servers_from_dhcp ? 1 : 0;
if (sntp_set_servers_from_dhcp != new_mode) {
sntp_set_servers_from_dhcp = new_mode;
}
}
#endif /* SNTP_GET_SERVERS_FROM_DHCP */
/**
* @ingroup sntp
* Initialize one of the NTP servers by IP address
*
* @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS
* @param server IP address of the NTP server to set
*/
void
sntp_setserver(u8_t idx, const ip_addr_t *server)
{
if (idx < SNTP_MAX_SERVERS) {
if (server != NULL) {
sntp_servers[idx].addr = (*server);
} else {
ip_addr_set_zero(&sntp_servers[idx].addr);
}
#if SNTP_SERVER_DNS
sntp_servers[idx].name = NULL;
#endif
}
}
#if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP
/**
* Initialize one of the NTP servers by IP address, required by DHCP
*
* @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
* @param dnsserver IP address of the NTP server to set
*/
void
dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
{
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n",
(sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));
if (sntp_set_servers_from_dhcp && num) {
u8_t i;
for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {
ip_addr_t addr;
ip_addr_copy_from_ip4(addr, server[i]);
sntp_setserver(i, &addr);
}
for (i = num; i < SNTP_MAX_SERVERS; i++) {
sntp_setserver(i, NULL);
}
}
}
#endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */
/**
* @ingroup sntp
* Obtain one of the currently configured by IP address (or DHCP) NTP servers
*
* @param idx the index of the NTP server
* @return IP address of the indexed NTP server or "ip_addr_any" if the NTP
* server has not been configured by address (or at all).
*/
const ip_addr_t*
sntp_getserver(u8_t idx)
{
if (idx < SNTP_MAX_SERVERS) {
return &sntp_servers[idx].addr;
}
return IP_ADDR_ANY;
}
#if SNTP_SERVER_DNS
/**
* Initialize one of the NTP servers by name
*
* @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
* @param dnsserver DNS name of the NTP server to set, to be resolved at contact time
*/
void
sntp_setservername(u8_t idx, char *server)
{
if (idx < SNTP_MAX_SERVERS) {
sntp_servers[idx].name = server;
}
}
/**
* Obtain one of the currently configured by name NTP servers.
*
* @param numdns the index of the NTP server
* @return IP address of the indexed NTP server or NULL if the NTP
* server has not been configured by name (or at all)
*/
char *
sntp_getservername(u8_t idx)
{
if (idx < SNTP_MAX_SERVERS) {
return sntp_servers[idx].name;
}
return NULL;
}
#endif /* SNTP_SERVER_DNS */
#endif /* LWIP_UDP */

View File

@@ -1,417 +0,0 @@
/****************************************************************//**
*
* @file tftp_server.c
*
* @author Logan Gunthorpe <logang@deltatee.com>
* Dirk Ziegelmeier <dziegel@gmx.de>
*
* @brief Trivial File Transfer Protocol (RFC 1350)
*
* Copyright (c) Deltatee Enterprises Ltd. 2013
* 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.
*
* Author: Logan Gunthorpe <logang@deltatee.com>
* Dirk Ziegelmeier <dziegel@gmx.de>
*
*/
/**
* @defgroup tftp TFTP server
* @ingroup apps
*
* This is simple TFTP server for the lwIP raw API.
*/
#include "lwip/apps/tftp_server.h"
#if LWIP_UDP
#include "lwip/udp.h"
#include "lwip/timeouts.h"
#include "lwip/debug.h"
#define TFTP_MAX_PAYLOAD_SIZE 512
#define TFTP_HEADER_LENGTH 4
#define TFTP_RRQ 1
#define TFTP_WRQ 2
#define TFTP_DATA 3
#define TFTP_ACK 4
#define TFTP_ERROR 5
enum tftp_error {
TFTP_ERROR_FILE_NOT_FOUND = 1,
TFTP_ERROR_ACCESS_VIOLATION = 2,
TFTP_ERROR_DISK_FULL = 3,
TFTP_ERROR_ILLEGAL_OPERATION = 4,
TFTP_ERROR_UNKNOWN_TRFR_ID = 5,
TFTP_ERROR_FILE_EXISTS = 6,
TFTP_ERROR_NO_SUCH_USER = 7
};
#include <string.h>
struct tftp_state {
const struct tftp_context *ctx;
void *handle;
struct pbuf *last_data;
struct udp_pcb *upcb;
ip_addr_t addr;
u16_t port;
int timer;
int last_pkt;
u16_t blknum;
u8_t retries;
u8_t mode_write;
};
static struct tftp_state tftp_state;
static void tftp_tmr(void* arg);
static void
close_handle(void)
{
tftp_state.port = 0;
ip_addr_set_any(0, &tftp_state.addr);
if(tftp_state.last_data != NULL) {
pbuf_free(tftp_state.last_data);
tftp_state.last_data = NULL;
}
sys_untimeout(tftp_tmr, NULL);
if (tftp_state.handle) {
tftp_state.ctx->close(tftp_state.handle);
tftp_state.handle = NULL;
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: closing\n"));
}
}
static void
send_error(const ip_addr_t *addr, u16_t port, enum tftp_error code, const char *str)
{
int str_length = strlen(str);
struct pbuf* p;
u16_t* payload;
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + str_length + 1), PBUF_RAM);
if(p == NULL) {
return;
}
payload = (u16_t*) p->payload;
payload[0] = PP_HTONS(TFTP_ERROR);
payload[1] = lwip_htons(code);
MEMCPY(&payload[2], str, str_length + 1);
udp_sendto(tftp_state.upcb, p, addr, port);
pbuf_free(p);
}
static void
send_ack(u16_t blknum)
{
struct pbuf* p;
u16_t* payload;
p = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH, PBUF_RAM);
if(p == NULL) {
return;
}
payload = (u16_t*) p->payload;
payload[0] = PP_HTONS(TFTP_ACK);
payload[1] = lwip_htons(blknum);
udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
pbuf_free(p);
}
static void
resend_data(void)
{
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, tftp_state.last_data->len, PBUF_RAM);
if(p == NULL) {
return;
}
if(pbuf_copy(p, tftp_state.last_data) != ERR_OK) {
pbuf_free(p);
return;
}
udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
pbuf_free(p);
}
static void
send_data(void)
{
u16_t *payload;
int ret;
if(tftp_state.last_data != NULL) {
pbuf_free(tftp_state.last_data);
}
tftp_state.last_data = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH + TFTP_MAX_PAYLOAD_SIZE, PBUF_RAM);
if(tftp_state.last_data == NULL) {
return;
}
payload = (u16_t *) tftp_state.last_data->payload;
payload[0] = PP_HTONS(TFTP_DATA);
payload[1] = lwip_htons(tftp_state.blknum);
ret = tftp_state.ctx->read(tftp_state.handle, &payload[2], TFTP_MAX_PAYLOAD_SIZE);
if (ret < 0) {
send_error(&tftp_state.addr, tftp_state.port, TFTP_ERROR_ACCESS_VIOLATION, "Error occured while reading the file.");
close_handle();
return;
}
pbuf_realloc(tftp_state.last_data, (u16_t)(TFTP_HEADER_LENGTH + ret));
resend_data();
}
static void
recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
u16_t *sbuf = (u16_t *) p->payload;
int opcode;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(upcb);
if (((tftp_state.port != 0) && (port != tftp_state.port)) ||
(!ip_addr_isany_val(tftp_state.addr) && !ip_addr_cmp(&tftp_state.addr, addr))) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
pbuf_free(p);
return;
}
opcode = sbuf[0];
tftp_state.last_pkt = tftp_state.timer;
tftp_state.retries = 0;
switch (opcode) {
case PP_HTONS(TFTP_RRQ): /* fall through */
case PP_HTONS(TFTP_WRQ):
{
const char tftp_null = 0;
char filename[TFTP_MAX_FILENAME_LEN];
char mode[TFTP_MAX_MODE_LEN];
u16_t filename_end_offset;
u16_t mode_end_offset;
if(tftp_state.handle != NULL) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
break;
}
sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
/* find \0 in pbuf -> end of filename string */
filename_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), 2);
if((u16_t)(filename_end_offset-2) > sizeof(filename)) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Filename too long/not NULL terminated");
break;
}
pbuf_copy_partial(p, filename, filename_end_offset-2, 2);
/* find \0 in pbuf -> end of mode string */
mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset+1);
if((u16_t)(mode_end_offset-filename_end_offset) > sizeof(mode)) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Mode too long/not NULL terminated");
break;
}
pbuf_copy_partial(p, mode, mode_end_offset-filename_end_offset, filename_end_offset+1);
tftp_state.handle = tftp_state.ctx->open(filename, mode, opcode == PP_HTONS(TFTP_WRQ));
tftp_state.blknum = 1;
if (!tftp_state.handle) {
send_error(addr, port, TFTP_ERROR_FILE_NOT_FOUND, "Unable to open requested file.");
break;
}
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: %s request from ", (opcode == PP_HTONS(TFTP_WRQ)) ? "write" : "read"));
ip_addr_debug_print(TFTP_DEBUG | LWIP_DBG_STATE, addr);
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, (" for '%s' mode '%s'\n", filename, mode));
ip_addr_copy(tftp_state.addr, *addr);
tftp_state.port = port;
if (opcode == PP_HTONS(TFTP_WRQ)) {
tftp_state.mode_write = 1;
send_ack(0);
} else {
tftp_state.mode_write = 0;
send_data();
}
break;
}
case PP_HTONS(TFTP_DATA):
{
int ret;
u16_t blknum;
if (tftp_state.handle == NULL) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
break;
}
if (tftp_state.mode_write != 1) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a write connection");
break;
}
blknum = lwip_ntohs(sbuf[1]);
pbuf_header(p, -TFTP_HEADER_LENGTH);
ret = tftp_state.ctx->write(tftp_state.handle, p);
if (ret < 0) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file");
close_handle();
} else {
send_ack(blknum);
}
if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) {
close_handle();
}
break;
}
case PP_HTONS(TFTP_ACK):
{
u16_t blknum;
int lastpkt;
if (tftp_state.handle == NULL) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
break;
}
if (tftp_state.mode_write != 0) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a read connection");
break;
}
blknum = lwip_ntohs(sbuf[1]);
if (blknum != tftp_state.blknum) {
send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number");
break;
}
lastpkt = 0;
if (tftp_state.last_data != NULL) {
lastpkt = tftp_state.last_data->tot_len != (TFTP_MAX_PAYLOAD_SIZE + TFTP_HEADER_LENGTH);
}
if (!lastpkt) {
tftp_state.blknum++;
send_data();
} else {
close_handle();
}
break;
}
default:
send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation");
break;
}
pbuf_free(p);
}
static void
tftp_tmr(void* arg)
{
LWIP_UNUSED_ARG(arg);
tftp_state.timer++;
if (tftp_state.handle == NULL) {
return;
}
sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
if ((tftp_state.timer - tftp_state.last_pkt) > (TFTP_TIMEOUT_MSECS / TFTP_TIMER_MSECS)) {
if ((tftp_state.last_data != NULL) && (tftp_state.retries < TFTP_MAX_RETRIES)) {
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout, retrying\n"));
resend_data();
tftp_state.retries++;
} else {
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout\n"));
close_handle();
}
}
}
/** @ingroup tftp
* Initialize TFTP server.
* @param ctx TFTP callback struct
*/
err_t
tftp_init(const struct tftp_context *ctx)
{
err_t ret;
struct udp_pcb *pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
if (pcb == NULL) {
return ERR_MEM;
}
ret = udp_bind(pcb, IP_ANY_TYPE, TFTP_PORT);
if (ret != ERR_OK) {
udp_remove(pcb);
return ret;
}
tftp_state.handle = NULL;
tftp_state.port = 0;
tftp_state.ctx = ctx;
tftp_state.timer = 0;
tftp_state.last_data = NULL;
tftp_state.upcb = pcb;
udp_recv(pcb, recv, NULL);
return ERR_OK;
}
#endif /* LWIP_UDP */

View File

@@ -2,28 +2,6 @@
* @file
* Common functions used throughout the stack.
*
* 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_htons(x) your_htons
* \#define lwip_htonl(x) your_htonl
*
* Note lwip_ntohs() and lwip_ntohl() are merely references to the htonx counterparts.
*
* If you \#define them to htons() and htonl(), you should
* \#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from
* defining htonx/ntohx compatibility macros.
* @defgroup sys_nonstandard Non-standard functions
* @ingroup sys_layer
* lwIP provides default implementations for non-standard functions.
* These can be mapped to OS functions to reduce code footprint if desired.
* All defines related to this section must not be placed in lwipopts.h,
* but in arch/cc.h!
* These options cannot be \#defined in lwipopts.h since they are not options
* of lwIP itself, but options of the lwIP port to your system.
*/
/*
@@ -61,11 +39,21 @@
#include "lwip/opt.h"
#include "lwip/def.h"
#include <string.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 BYTE_ORDER == LITTLE_ENDIAN
#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
#if !defined(lwip_htons)
/**
* Convert an u16_t from host- to network byte order.
*
@@ -75,11 +63,21 @@
u16_t
lwip_htons(u16_t n)
{
return (u16_t)PP_HTONS(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);
}
#endif /* lwip_htons */
#if !defined(lwip_htonl)
/**
* Convert an u32_t from host- to network byte order.
*
@@ -89,134 +87,22 @@ lwip_htons(u16_t n)
u32_t
lwip_htonl(u32_t n)
{
return (u32_t)PP_HTONL(n);
return ((n & 0xff) << 24) |
((n & 0xff00) << 8) |
((n & 0xff0000UL) >> 8) |
((n & 0xff000000UL) >> 24);
}
#endif /* lwip_htonl */
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
#ifndef lwip_strnstr
/**
* @ingroup sys_nonstandard
* lwIP default implementation for strnstr() non-standard function.
* This can be \#defined to strnstr() depending on your platform port.
* Convert an u32_t from network- to host byte order.
*
* @param n u32_t in network byte order
* @return n in host byte order
*/
char*
lwip_strnstr(const char* buffer, const char* token, size_t n)
u32_t
lwip_ntohl(u32_t n)
{
const char* p;
size_t tokenlen = strlen(token);
if (tokenlen == 0) {
return LWIP_CONST_CAST(char *, buffer);
}
for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) {
if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) {
return LWIP_CONST_CAST(char *, p);
}
}
return NULL;
return lwip_htonl(n);
}
#endif
#ifndef lwip_stricmp
/**
* @ingroup sys_nonstandard
* lwIP default implementation for stricmp() non-standard function.
* This can be \#defined to stricmp() depending on your platform port.
*/
int
lwip_stricmp(const char* str1, const char* str2)
{
char c1, c2;
do {
c1 = *str1++;
c2 = *str2++;
if (c1 != c2) {
char c1_upc = c1 | 0x20;
if ((c1_upc >= 'a') && (c1_upc <= 'z')) {
/* characters are not equal an one is in the alphabet range:
downcase both chars and check again */
char c2_upc = c2 | 0x20;
if (c1_upc != c2_upc) {
/* still not equal */
/* don't care for < or > */
return 1;
}
} else {
/* characters are not equal but none is in the alphabet range */
return 1;
}
}
} while (c1 != 0);
return 0;
}
#endif
#ifndef lwip_strnicmp
/**
* @ingroup sys_nonstandard
* lwIP default implementation for strnicmp() non-standard function.
* This can be \#defined to strnicmp() depending on your platform port.
*/
int
lwip_strnicmp(const char* str1, const char* str2, size_t len)
{
char c1, c2;
do {
c1 = *str1++;
c2 = *str2++;
if (c1 != c2) {
char c1_upc = c1 | 0x20;
if ((c1_upc >= 'a') && (c1_upc <= 'z')) {
/* characters are not equal an one is in the alphabet range:
downcase both chars and check again */
char c2_upc = c2 | 0x20;
if (c1_upc != c2_upc) {
/* still not equal */
/* don't care for < or > */
return 1;
}
} else {
/* characters are not equal but none is in the alphabet range */
return 1;
}
}
} while (len-- && c1 != 0);
return 0;
}
#endif
#ifndef lwip_itoa
/**
* @ingroup sys_nonstandard
* lwIP default implementation for itoa() non-standard function.
* This can be \#defined to itoa() or snprintf(result, bufsize, "%d", number) depending on your platform port.
*/
void
lwip_itoa(char* result, size_t bufsize, int number)
{
const int base = 10;
char* ptr = result, *ptr1 = result, tmp_char;
int tmp_value;
LWIP_UNUSED_ARG(bufsize);
do {
tmp_value = number;
number /= base;
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - number * base)];
} while(number);
/* Apply negative sign */
if (tmp_value < 0) {
*ptr++ = '-';
}
*ptr-- = '\0';
while(ptr1 < ptr) {
tmp_char = *ptr;
*ptr--= *ptr1;
*ptr1++ = tmp_char;
}
}
#endif
#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,9 +6,9 @@
/*
* 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,22 +17,23 @@
* 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"
@@ -48,38 +49,15 @@
#include "lwip/ip.h"
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/priv/tcp_priv.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/timeouts.h"
#include "lwip/etharp.h"
#include "lwip/ip6.h"
#include "lwip/nd6.h"
#include "lwip/mld6.h"
#include "lwip/timers.h"
#include "netif/etharp.h"
#include "lwip/api.h"
#include "netif/ppp/ppp_opts.h"
#include "netif/ppp/ppp_impl.h"
#ifndef LWIP_SKIP_PACKING_CHECK
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct packed_struct_test
{
PACK_STRUCT_FLD_8(u8_t dummy1);
PACK_STRUCT_FIELD(u32_t dummy2);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define PACKED_STRUCT_TEST_EXPECTED_SIZE 5
#endif
/* Compile-time sanity checks for configuration errors.
* These can be done independently of LWIP_DEBUG, without penalty.
*/
@@ -92,11 +70,17 @@ PACK_STRUCT_END
#if (!LWIP_UDP && LWIP_UDPLITE)
#error "If you want to use UDP Lite, 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_DHCP)
#error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
#if (!LWIP_UDP && LWIP_MULTICAST_TX_OPTIONS)
#error "If you want to use IGMP/LWIP_MULTICAST_TX_OPTIONS, you have to define LWIP_UDP=1 in your lwipopts.h"
#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"
@@ -117,44 +101,20 @@ PACK_STRUCT_END
#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 (LWIP_IGMP && !LWIP_MULTICAST_TX_OPTIONS)
#error "If you want to use IGMP, you have to define LWIP_MULTICAST_TX_OPTIONS==1 in your lwipopts.h"
#endif
#if (LWIP_IGMP && !LWIP_IPV4)
#error "IGMP needs LWIP_IPV4 enabled in your lwipopts.h"
#endif
#if (LWIP_MULTICAST_TX_OPTIONS && !LWIP_IPV4)
#error "LWIP_MULTICAST_TX_OPTIONS needs LWIP_IPV4 enabled in your lwipopts.h"
#endif
#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
#endif
/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0)))
#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))
#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
#endif
#endif /* !MEMP_MEM_MALLOC */
#if LWIP_WND_SCALE
#if (LWIP_TCP && (TCP_WND > 0xffffffff))
#error "If you want to use TCP, TCP_WND must fit in an u32_t, so, you have to reduce it in your lwipopts.h"
#endif
#if (LWIP_TCP && (TCP_RCV_SCALE > 14))
#error "The maximum valid window scale value is 14!"
#endif
#if (LWIP_TCP && (TCP_WND > (0xFFFFU << TCP_RCV_SCALE)))
#error "TCP_WND is bigger than the configured LWIP_WND_SCALE allows!"
#endif
#if (LWIP_TCP && ((TCP_WND >> TCP_RCV_SCALE) == 0))
#error "TCP_WND is too small for the configured LWIP_WND_SCALE (results in zero window)!"
#endif
#else /* LWIP_WND_SCALE */
#if (LWIP_TCP && (TCP_WND > 0xffff))
#error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h (or enable window scaling)"
#error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
#endif
#endif /* LWIP_WND_SCALE */
#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
@@ -164,7 +124,7 @@ PACK_STRUCT_END
#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
#if (LWIP_TCP && TCP_LISTEN_BACKLOG && ((TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff)))
#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))
#error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t"
#endif
#if (LWIP_NETIF_API && (NO_SYS==1))
@@ -173,11 +133,8 @@ PACK_STRUCT_END
#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
#error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
#endif
#if (LWIP_PPP_API && (NO_SYS==1))
#error "If you want to use PPP API, you have to define NO_SYS=0 in your lwipopts.h"
#endif
#if (LWIP_PPP_API && (PPP_SUPPORT==0))
#error "If you want to use PPP API, you have to enable PPP_SUPPORT in your lwipopts.h"
#if (!LWIP_NETCONN && LWIP_SOCKET)
#error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h"
#endif
#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP)
#error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h"
@@ -188,6 +145,12 @@ PACK_STRUCT_END
#if (!LWIP_ARP && LWIP_AUTOIP)
#error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h"
#endif
#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0))
#error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h"
#endif
#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))
#error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"
#endif
#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))
#error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"
#endif
@@ -203,27 +166,24 @@ PACK_STRUCT_END
#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 && !PPPOL2TP_SUPPORT
#error "PPP_SUPPORT needs at least one of PPPOS_SUPPORT, PPPOE_SUPPORT or PPPOL2TP_SUPPORT turned on"
#endif
#if PPP_SUPPORT && !PPP_IPV4_SUPPORT && !PPP_IPV6_SUPPORT
#error "PPP_SUPPORT needs PPP_IPV4_SUPPORT and/or PPP_IPV6_SUPPORT turned on"
#endif
#if PPP_SUPPORT && PPP_IPV4_SUPPORT && !LWIP_IPV4
#error "PPP_IPV4_SUPPORT needs LWIP_IPV4 turned on"
#endif
#if PPP_SUPPORT && PPP_IPV6_SUPPORT && !LWIP_IPV6
#error "PPP_IPV6_SUPPORT needs LWIP_IPV6 turned on"
#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT
#error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on"
#endif
#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT)
#error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT"
#endif
#if LWIP_IGMP && !defined(LWIP_RAND)
#error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
#endif
#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING
#error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too"
#endif
#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE
#error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets"
#endif
#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF
#error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues"
#endif
#if LWIP_NETCONN && LWIP_TCP
#if NETCONN_COPY != TCP_WRITE_FLAG_COPY
#error "NETCONN_COPY != TCP_WRITE_FLAG_COPY"
@@ -231,9 +191,12 @@ PACK_STRUCT_END
#if NETCONN_MORE != TCP_WRITE_FLAG_MORE
#error "NETCONN_MORE != TCP_WRITE_FLAG_MORE"
#endif
#endif /* LWIP_NETCONN && LWIP_TCP */
#endif /* LWIP_NETCONN && LWIP_TCP */
#if LWIP_SOCKET
/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
#if SO_ACCEPTCONN != SOF_ACCEPTCONN
#error "SO_ACCEPTCONN != SOF_ACCEPTCONN"
#endif
#if SO_REUSEADDR != SOF_REUSEADDR
#error "WARNING: SO_REUSEADDR != SOF_REUSEADDR"
#endif
@@ -243,6 +206,9 @@ PACK_STRUCT_END
#if SO_BROADCAST != SOF_BROADCAST
#error "WARNING: SO_BROADCAST != SOF_BROADCAST"
#endif
#if SO_LINGER != SOF_LINGER
#error "WARNING: SO_LINGER != SOF_LINGER"
#endif
#endif /* LWIP_SOCKET */
@@ -251,6 +217,9 @@ PACK_STRUCT_END
#ifdef MEMP_NUM_TCPIP_MSG
#error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h."
#endif
#ifdef MEMP_NUM_API_MSG
#error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h."
#endif
#ifdef TCP_REXMIT_DEBUG
#error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h."
#endif
@@ -263,9 +232,6 @@ PACK_STRUCT_END
#ifdef ETHARP_ALWAYS_INSERT
#error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."
#endif
#if !NO_SYS && LWIP_TCPIP_CORE_LOCKING && LWIP_COMPAT_MUTEX && !defined(LWIP_COMPAT_MUTEX_ALLOWED)
#error "LWIP_COMPAT_MUTEX cannot prevent priority inversion. It is recommended to implement priority-aware mutexes. (Define LWIP_COMPAT_MUTEX_ALLOWED to disable this error.)"
#endif
#ifndef LWIP_DISABLE_TCP_SANITY_CHECKS
#define LWIP_DISABLE_TCP_SANITY_CHECKS 0
@@ -275,9 +241,9 @@ PACK_STRUCT_END
#endif
/* MEMP sanity checks */
#if MEMP_MEM_MALLOC
#if !LWIP_DISABLE_MEMP_SANITY_CHECKS
#if LWIP_NETCONN || LWIP_SOCKET
#if LWIP_NETCONN
#if MEMP_MEM_MALLOC
#if !MEMP_NUM_NETCONN && LWIP_SOCKET
#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN cannot be 0 when using sockets!"
#endif
@@ -285,15 +251,9 @@ PACK_STRUCT_END
#if MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB)
#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN. If you know what you are doing, define LWIP_DISABLE_MEMP_SANITY_CHECKS to 1 to disable this error."
#endif
#endif /* LWIP_NETCONN || LWIP_SOCKET */
#endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */
#if MEM_USE_POOLS
#error "MEMP_MEM_MALLOC and MEM_USE_POOLS cannot be enabled at the same time"
#endif
#ifdef LWIP_HOOK_MEMP_AVAILABLE
#error "LWIP_HOOK_MEMP_AVAILABLE doesn't make sense with MEMP_MEM_MALLOC"
#endif
#endif /* MEMP_MEM_MALLOC */
#endif /* LWIP_NETCONN */
#endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */
/* TCP sanity checks */
#if !LWIP_DISABLE_TCP_SANITY_CHECKS
@@ -310,16 +270,10 @@ PACK_STRUCT_END
#if TCP_SNDLOWAT >= TCP_SND_BUF
#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_SNDLOWAT >= (0xFFFF - (4 * TCP_MSS))
#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must at least be 4*MSS below u16_t overflow!"
#endif
#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN
#error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (PBUF_POOL_BUFSIZE <= (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))
#error "lwip_sanity_check: WARNING: PBUF_POOL_BUFSIZE does not provide enough space for protocol headers. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))))
#if !MEMP_MEM_MALLOC && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))))
#error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_WND < TCP_MSS
@@ -329,22 +283,11 @@ PACK_STRUCT_END
#endif /* !LWIP_DISABLE_TCP_SANITY_CHECKS */
/**
* @ingroup lwip_nosys
* Initialize all modules.
* Use this in NO_SYS mode. Use tcpip_init() otherwise.
* Perform Sanity check of user-configurable values, and initialize all modules.
*/
void
lwip_init(void)
{
#ifndef LWIP_SKIP_CONST_CHECK
int a;
LWIP_UNUSED_ARG(a);
LWIP_ASSERT("LWIP_CONST_CAST not implemented correctly. Check your lwIP port.", LWIP_CONST_CAST(void*, &a) == &a);
#endif
#ifndef LWIP_SKIP_PACKING_CHECK
LWIP_ASSERT("Struct packing not implemented correctly. Check your lwIP port.", sizeof(struct packed_struct_test) == PACKED_STRUCT_TEST_EXPECTED_SIZE);
#endif
/* Modules initialization */
stats_init();
#if !NO_SYS
@@ -354,12 +297,13 @@ lwip_init(void)
memp_init();
pbuf_init();
netif_init();
#if LWIP_IPV4
#if LWIP_SOCKET
lwip_socket_init();
#endif /* LWIP_SOCKET */
ip_init();
#if LWIP_ARP
etharp_init();
#endif /* LWIP_ARP */
#endif /* LWIP_IPV4 */
#if LWIP_RAW
raw_init();
#endif /* LWIP_RAW */
@@ -369,16 +313,19 @@ 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 */
#if LWIP_IGMP
igmp_init();
#endif /* LWIP_IGMP */
#if LWIP_DNS
dns_init();
#endif /* LWIP_DNS */
#if PPP_SUPPORT
ppp_init();
#endif
#if LWIP_TIMERS
sys_timeouts_init();
#endif /* LWIP_TIMERS */

View File

@@ -1,124 +0,0 @@
/**
* @file
* Common IPv4 and IPv6 code
*
* @defgroup ip IP
* @ingroup callbackstyle_api
*
* @defgroup ip4 IPv4
* @ingroup ip
*
* @defgroup ip6 IPv6
* @ingroup ip
*
* @defgroup ipaddr IP address handling
* @ingroup infrastructure
*
* @defgroup ip4addr IPv4 only
* @ingroup ipaddr
*
* @defgroup ip6addr IPv6 only
* @ingroup ipaddr
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#if LWIP_IPV4 || LWIP_IPV6
#include "lwip/ip_addr.h"
#include "lwip/ip.h"
/** Global data for both IPv4 and IPv6 */
struct ip_globals ip_data;
#if LWIP_IPV4 && LWIP_IPV6
const ip_addr_t ip_addr_any_type = IPADDR_ANY_TYPE_INIT;
/**
* @ingroup ipaddr
* Convert IP address string (both versions) to numeric.
* The version is auto-detected from the string.
*
* @param cp IP address string to convert
* @param addr conversion result is stored here
* @return 1 on success, 0 on error
*/
int
ipaddr_aton(const char *cp, ip_addr_t *addr)
{
if (cp != NULL) {
const char* c;
for (c = cp; *c != 0; c++) {
if (*c == ':') {
/* contains a colon: IPv6 address */
if (addr) {
IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V6);
}
return ip6addr_aton(cp, ip_2_ip6(addr));
} else if (*c == '.') {
/* contains a dot: IPv4 address */
break;
}
}
/* call ip4addr_aton as fallback or if IPv4 was found */
if (addr) {
IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V4);
}
return ip4addr_aton(cp, ip_2_ip4(addr));
}
return 0;
}
/**
* @ingroup lwip_nosys
* If both IP versions are enabled, this function can dispatch packets to the correct one.
* Don't call directly, pass to netif_add() and call netif->input().
*/
err_t
ip_input(struct pbuf *p, struct netif *inp)
{
if (p != NULL) {
if (IP_HDR_GET_VERSION(p->payload) == 6) {
return ip6_input(p, inp);
}
return ip4_input(p, inp);
}
return ERR_VAL;
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#endif /* LWIP_IPV4 || LWIP_IPV6 */

View File

@@ -2,28 +2,6 @@
* @file
* AutoIP Automatic LinkLocal IP Configuration
*
* This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
* with RFC 3927.
*
* @defgroup autoip AUTOIP
* @ingroup ip4
* AUTOIP related functions
* USAGE:
*
* define @ref LWIP_AUTOIP 1 in your lwipopts.h
* Options:
* AUTOIP_TMR_INTERVAL msecs,
* I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
* Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
*
* Without DHCP:
* - Call autoip_start() after netif_add().
*
* With DHCP:
* - define @ref LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
* - Configure your DHCP Client.
*
* @see netifapi_autoip
*/
/*
@@ -54,22 +32,58 @@
* OF SUCH DAMAGE.
*
* Author: Dominik Spies <kontakt@dspies.de>
*
* This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
* with RFC 3927.
*
*
* Please coordinate changes and requests with Dominik Spies
* <kontakt@dspies.de>
*/
/*******************************************************************************
* USAGE:
*
* define LWIP_AUTOIP 1 in your lwipopts.h
*
* If you don't use tcpip.c (so, don't call, you don't call tcpip_init):
* - First, call autoip_init().
* - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,
* that should be defined in autoip.h.
* I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
* Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
*
* Without DHCP:
* - Call autoip_start() after netif_add().
*
* With DHCP:
* - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
* - Configure your DHCP Client.
*
*/
#include "lwip/opt.h"
#if LWIP_IPV4 && LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
#include "lwip/mem.h"
/* #include "lwip/udp.h" */
#include "lwip/udp.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/autoip.h"
#include "lwip/etharp.h"
#include "lwip/prot/autoip.h"
#include "netif/etharp.h"
#include <stdlib.h>
#include <string.h>
/* 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
@@ -77,7 +91,7 @@
((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
((u32_t)((netif->hwaddr[4]) & 0xff))) + \
(netif_autoip_data(netif)? netif_autoip_data(netif)->tried_llipaddr : 0))
(netif->autoip?netif->autoip->tried_llipaddr:0))
#endif /* LWIP_AUTOIP_RAND */
/**
@@ -86,34 +100,46 @@
*/
#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
lwip_htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
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 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);
/* configure interface for use with current LL IP-Address */
static err_t autoip_bind(struct netif *netif);
/* start sending probes for llipaddr */
static void autoip_start_probing(struct netif *netif);
/**
* @ingroup autoip
* Set a statically allocated struct autoip to work with.
/** 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 autoip (uninitialised) autoip struct allocated by the application
* @param dhcp (uninitialised) dhcp struct allocated by the application
*/
void
autoip_set_struct(struct netif *netif, struct autoip *autoip)
{
LWIP_ASSERT("netif != NULL", netif != NULL);
LWIP_ASSERT("autoip != NULL", autoip != NULL);
LWIP_ASSERT("netif already has a struct autoip set",
netif_autoip_data(netif) == 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_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip);
netif->autoip = autoip;
}
/** Restart AutoIP client and check the next address (conflict detected)
@@ -123,8 +149,7 @@ autoip_set_struct(struct netif *netif, struct autoip *autoip)
static void
autoip_restart(struct netif *netif)
{
struct autoip* autoip = netif_autoip_data(netif);
autoip->tried_llipaddr++;
netif->autoip->tried_llipaddr++;
autoip_start(netif);
}
@@ -134,27 +159,30 @@ autoip_restart(struct netif *netif)
static void
autoip_handle_arp_conflict(struct netif *netif)
{
struct autoip* autoip = netif_autoip_data(netif);
/* Somehow detect if we are defending or retreating */
unsigned char defend = 1; /* tbd */
/* RFC3927, 2.5 "Conflict Detection and Defense" allows two options where
a) means retreat on the first conflict and
b) allows to keep an already configured address when having only one
conflict in 10 seconds
We use option b) since it helps to improve the chance that one of the two
conflicting hosts may be able to retain its address. */
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,
("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
if (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,
("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
/* Active TCP sessions are aborted when removing the ip addresss */
autoip_restart(netif);
/* TODO: close all TCP sessions */
autoip_restart(netif);
} else {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
autoip_arp_announce(netif);
netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
}
} else {
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);
autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
/* TODO: close all TCP sessions */
autoip_restart(netif);
}
}
@@ -165,18 +193,16 @@ autoip_handle_arp_conflict(struct netif *netif)
* @param ipaddr ip address to initialize
*/
static void
autoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr)
autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
{
struct autoip* autoip = netif_autoip_data(netif);
/* 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 */
u32_t addr = lwip_ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
addr += autoip->tried_llipaddr;
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 */
/* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
if (addr < AUTOIP_RANGE_START) {
addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
@@ -186,11 +212,11 @@ autoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr)
}
LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
(addr <= AUTOIP_RANGE_END));
ip4_addr_set_u32(ipaddr, lwip_htonl(addr));
ip4_addr_set_u32(ipaddr, htonl(addr));
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
(u16_t)(autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
(u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
}
@@ -202,9 +228,9 @@ autoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr)
static err_t
autoip_arp_probe(struct netif *netif)
{
struct autoip* autoip = netif_autoip_data(netif);
/* this works because netif->ip_addr is ANY */
return etharp_request(netif, &autoip->llipaddr);
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
(struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, &ethzero,
&netif->autoip->llipaddr, ARP_REQUEST);
}
/**
@@ -215,7 +241,9 @@ autoip_arp_probe(struct netif *netif)
static err_t
autoip_arp_announce(struct netif *netif)
{
return etharp_gratuitous(netif);
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
(struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, &ethzero,
&netif->autoip->llipaddr, ARP_REQUEST);
}
/**
@@ -226,8 +254,8 @@ autoip_arp_announce(struct netif *netif)
static err_t
autoip_bind(struct netif *netif)
{
struct autoip* autoip = netif_autoip_data(netif);
ip4_addr_t sn_mask, gw_addr;
struct autoip *autoip = netif->autoip;
ip_addr_t sn_mask, gw_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",
@@ -238,14 +266,17 @@ autoip_bind(struct netif *netif)
IP4_ADDR(&sn_mask, 255, 255, 0, 0);
IP4_ADDR(&gw_addr, 0, 0, 0, 0);
netif_set_addr(netif, &autoip->llipaddr, &sn_mask, &gw_addr);
/* interface is used by routing now that an address is set */
netif_set_ipaddr(netif, &autoip->llipaddr);
netif_set_netmask(netif, &sn_mask);
netif_set_gw(netif, &gw_addr);
/* bring the interface up */
netif_set_up(netif);
return ERR_OK;
}
/**
* @ingroup autoip
* Start AutoIP client
*
* @param netif network interface on which start the AutoIP client
@@ -253,15 +284,19 @@ autoip_bind(struct netif *netif)
err_t
autoip_start(struct netif *netif)
{
struct autoip* autoip = netif_autoip_data(netif);
struct autoip *autoip = netif->autoip;
err_t result = ERR_OK;
LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);
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_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
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],
@@ -278,13 +313,13 @@ autoip_start(struct netif *netif)
}
memset(autoip, 0, sizeof(struct autoip));
/* store this AutoIP client in the netif */
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip);
netif->autoip = autoip;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
} else {
autoip->state = AUTOIP_STATE_OFF;
autoip->ttw = 0;
autoip->sent_num = 0;
ip4_addr_set_zero(&autoip->llipaddr);
ip_addr_set_zero(&autoip->llipaddr);
autoip->lastconflict = 0;
}
@@ -297,24 +332,24 @@ autoip_start(struct netif *netif)
static void
autoip_start_probing(struct netif *netif)
{
struct autoip* autoip = netif_autoip_data(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(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
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
* chosen out of 0 to PROBE_WAIT seconds.
* choosen out of 0 to PROBE_WAIT seconds.
* compliant to RFC 3927 Section 2.2.1
*/
autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND));
/*
* if we tried more then MAX_CONFLICTS we must limit our rate for
* acquiring and probing address
* accquiring and probing address
* compliant to RFC 3927 Section 2.2.1
*/
if (autoip->tried_llipaddr > MAX_CONFLICTS) {
@@ -331,15 +366,13 @@ autoip_start_probing(struct netif *netif)
void
autoip_network_changed(struct netif *netif)
{
struct autoip* autoip = netif_autoip_data(netif);
if (autoip && (autoip->state != AUTOIP_STATE_OFF)) {
if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
netif_set_down(netif);
autoip_start_probing(netif);
}
}
/**
* @ingroup autoip
* Stop AutoIP client
*
* @param netif network interface on which stop the AutoIP client
@@ -347,14 +380,8 @@ autoip_network_changed(struct netif *netif)
err_t
autoip_stop(struct netif *netif)
{
struct autoip* autoip = netif_autoip_data(netif);
if (autoip != NULL) {
autoip->state = AUTOIP_STATE_OFF;
if (ip4_addr_islinklocal(netif_ip4_addr(netif))) {
netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
}
}
netif->autoip->state = AUTOIP_STATE_OFF;
netif_set_down(netif);
return ERR_OK;
}
@@ -362,80 +389,78 @@ autoip_stop(struct netif *netif)
* Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds
*/
void
autoip_tmr(void)
autoip_tmr()
{
struct netif *netif = netif_list;
/* loop through netif's */
while (netif != NULL) {
struct autoip* autoip = netif_autoip_data(netif);
/* only act on AutoIP configured interfaces */
if (autoip != NULL) {
if (autoip->lastconflict > 0) {
autoip->lastconflict--;
if (netif->autoip != NULL) {
if (netif->autoip->lastconflict > 0) {
netif->autoip->lastconflict--;
}
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",
(u16_t)(autoip->state), autoip->ttw));
(u16_t)(netif->autoip->state), netif->autoip->ttw));
if (autoip->ttw > 0) {
autoip->ttw--;
}
switch(autoip->state) {
switch(netif->autoip->state) {
case AUTOIP_STATE_PROBING:
if (autoip->ttw == 0) {
if (autoip->sent_num >= PROBE_NUM) {
/* Switch to ANNOUNCING: now we can bind to an IP address and use it */
autoip->state = AUTOIP_STATE_ANNOUNCING;
autoip_bind(netif);
/* autoip_bind() calls netif_set_addr(): this triggers a gratuitous ARP
which counts as an announcement */
autoip->sent_num = 1;
autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
if (netif->autoip->ttw > 0) {
netif->autoip->ttw--;
} else {
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(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
} else {
autoip_arp_probe(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() PROBING Sent Probe\n"));
autoip->sent_num++;
if (autoip->sent_num == PROBE_NUM) {
/* calculate time to wait to for announce */
autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
} else {
/* calculate time to wait to next probe */
autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
}
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_tmr() PROBING Sent Probe\n"));
netif->autoip->sent_num++;
/* calculate time to wait to next probe */
netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
}
}
break;
case AUTOIP_STATE_ANNOUNCING:
if (autoip->ttw == 0) {
autoip_arp_announce(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() ANNOUNCING Sent Announce\n"));
autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
autoip->sent_num++;
if (netif->autoip->ttw > 0) {
netif->autoip->ttw--;
} else {
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.
*
* autoip_bind calls netif_set_up. This triggers a gratuitous ARP
* which counts as an announcement.
*/
autoip_bind(netif);
} else {
autoip_arp_announce(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_tmr() ANNOUNCING Sent Announce\n"));
}
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
netif->autoip->sent_num++;
if (autoip->sent_num >= ANNOUNCE_NUM) {
autoip->state = AUTOIP_STATE_BOUND;
autoip->sent_num = 0;
autoip->ttw = 0;
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(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
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;
default:
/* nothing to do in other states */
break;
}
}
/* proceed to next network interface */
@@ -444,7 +469,7 @@ autoip_tmr(void)
}
/**
* Handles every incoming ARP Packet, called by etharp_input().
* Handles every incoming ARP Packet, called by etharp_arp_input.
*
* @param netif network interface to use for autoip processing
* @param hdr Incoming ARP packet
@@ -452,35 +477,34 @@ autoip_tmr(void)
void
autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
{
struct autoip* autoip = netif_autoip_data(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
if ((autoip != NULL) && (autoip->state != AUTOIP_STATE_OFF)) {
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
*/
ip4_addr_t sipaddr, dipaddr;
ip_addr_t sipaddr, dipaddr;
struct eth_addr netifaddr;
ETHADDR16_COPY(netifaddr.addr, netif->hwaddr);
/* Copy struct ip4_addr2 to aligned ip4_addr, to support compilers without
/* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
* structure packing (not using structure copy which breaks strict-aliasing rules).
*/
IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
if (autoip->state == AUTOIP_STATE_PROBING) {
if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
(netif->autoip->sent_num == 0))) {
/* RFC 3927 Section 2.2.1:
* from beginning to after ANNOUNCE_WAIT
* seconds we have a conflict if
* ip.src == llipaddr OR
* ip.dst == llipaddr && hw.src != own hwaddr
*/
if ((ip4_addr_cmp(&sipaddr, &autoip->llipaddr)) ||
(ip4_addr_isany_val(sipaddr) &&
ip4_addr_cmp(&dipaddr, &autoip->llipaddr) &&
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 | LWIP_DBG_LEVEL_WARNING,
("autoip_arp_reply(): Probe Conflict detected\n"));
@@ -491,7 +515,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
* in any state we have a conflict if
* ip.src == llipaddr && hw.src != own hwaddr
*/
if (ip4_addr_cmp(&sipaddr, &autoip->llipaddr) &&
if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
!eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
@@ -501,27 +525,4 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
}
}
/** check if AutoIP supplied netif->ip_addr
*
* @param netif the netif to check
* @return 1 if AutoIP supplied netif->ip_addr (state BOUND or ANNOUNCING),
* 0 otherwise
*/
u8_t
autoip_supplied_address(const struct netif *netif)
{
if ((netif != NULL) && (netif_autoip_data(netif) != NULL)) {
struct autoip* autoip = netif_autoip_data(netif);
return (autoip->state == AUTOIP_STATE_BOUND) || (autoip->state == AUTOIP_STATE_ANNOUNCING);
}
return 0;
}
u8_t
autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr)
{
struct autoip* autoip = netif_autoip_data(netif);
return (autoip != NULL) && ip4_addr_cmp(addr, &(autoip->llipaddr));
}
#endif /* LWIP_IPV4 && LWIP_AUTOIP */
#endif /* LWIP_AUTOIP */

View File

@@ -41,20 +41,17 @@
#include "lwip/opt.h"
#if LWIP_IPV4 && LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/icmp.h"
#include "lwip/inet_chksum.h"
#include "lwip/ip.h"
#include "lwip/def.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include <string.h>
#ifdef LWIP_HOOK_FILENAME
#include LWIP_HOOK_FILENAME
#endif
/** 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) */
@@ -73,7 +70,7 @@ static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
* Currently only processes icmp echo requests and sends
* out the echo response.
*
* @param p the icmp echo request packet, p->payload pointing to the icmp header
* @param p the icmp echo request packet, p->payload pointing to the ip header
* @param inp the netif on which this packet was received
*/
void
@@ -84,20 +81,16 @@ icmp_input(struct pbuf *p, struct netif *inp)
u8_t code;
#endif /* LWIP_DEBUG */
struct icmp_echo_hdr *iecho;
const struct ip_hdr *iphdr_in;
u16_t hlen;
const ip4_addr_t* src;
struct ip_hdr *iphdr;
s16_t hlen;
ICMP_STATS_INC(icmp.recv);
MIB2_STATS_INC(mib2.icmpinmsgs);
snmp_inc_icmpinmsgs();
iphdr_in = ip4_current_header();
hlen = IPH_HL(iphdr_in) * 4;
if (hlen < IP_HLEN) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short IP header (%"S16_F" bytes) received\n", hlen));
goto lenerr;
}
if (p->len < sizeof(u16_t)*2) {
iphdr = (struct ip_hdr *)p->payload;
hlen = IPH_HL(iphdr) * 4;
if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
goto lenerr;
}
@@ -110,87 +103,83 @@ icmp_input(struct pbuf *p, struct netif *inp)
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). */
MIB2_STATS_INC(mib2.icmpinechoreps);
break;
break;
case ICMP_ECHO:
MIB2_STATS_INC(mib2.icmpinechos);
src = ip4_current_dest_addr();
/* multicast destination address? */
if (ip4_addr_ismulticast(ip4_current_dest_addr())) {
#if LWIP_MULTICAST_PING
/* For multicast, use address of receiving interface as source address */
src = netif_ip4_addr(inp);
#else /* LWIP_MULTICAST_PING */
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast pings\n"));
goto icmperr;
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
{
int accepted = 1;
#if !LWIP_MULTICAST_PING
/* multicast destination address? */
if (ip_addr_ismulticast(&current_iphdr_dest)) {
accepted = 0;
}
#endif /* LWIP_MULTICAST_PING */
}
/* broadcast destination address? */
if (ip4_addr_isbroadcast(ip4_current_dest_addr(), ip_current_netif())) {
#if LWIP_BROADCAST_PING
/* For broadcast, use address of receiving interface as source address */
src = netif_ip4_addr(inp);
#else /* LWIP_BROADCAST_PING */
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to broadcast pings\n"));
goto icmperr;
#if !LWIP_BROADCAST_PING
/* broadcast destination address? */
if (ip_addr_isbroadcast(&current_iphdr_dest, 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"));
goto lenerr;
}
#if CHECKSUM_CHECK_ICMP
IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP) {
if (inet_chksum_pbuf(p) != 0) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
pbuf_free(p);
ICMP_STATS_INC(icmp.chkerr);
MIB2_STATS_INC(mib2.icmpinerrors);
return;
}
if (inet_chksum_pbuf(p) != 0) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
pbuf_free(p);
ICMP_STATS_INC(icmp.chkerr);
snmp_inc_icmpinerrors();
return;
}
#endif
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
if (pbuf_header(p, (s16_t)(hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN))) {
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
*/
struct pbuf *r;
/* switch p->payload to ip header */
if (pbuf_header(p, hlen)) {
LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
goto memerr;
}
/* allocate new packet buffer with space for link headers */
r = pbuf_alloc(PBUF_LINK, p->tot_len + hlen, PBUF_RAM);
r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
if (r == NULL) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
goto icmperr;
goto memerr;
}
if (r->len < hlen + sizeof(struct icmp_echo_hdr)) {
LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("first pbuf cannot hold the ICMP header"));
pbuf_free(r);
goto icmperr;
}
/* copy the ip header */
MEMCPY(r->payload, iphdr_in, hlen);
/* switch r->payload back to icmp header (cannot fail) */
if (pbuf_header(r, (s16_t)-hlen)) {
LWIP_ASSERT("icmp_input: moving r->payload to icmp header failed\n", 0);
pbuf_free(r);
goto icmperr;
}
/* copy the rest of the packet without ip header */
LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
(r->len >= hlen + sizeof(struct icmp_echo_hdr)));
/* copy the whole packet including ip header */
if (pbuf_copy(r, p) != ERR_OK) {
LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("icmp_input: copying to new pbuf failed"));
pbuf_free(r);
goto icmperr;
LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
goto memerr;
}
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);
goto memerr;
}
/* free the original p */
pbuf_free(p);
/* we now have an identical copy of p that has room for link headers */
p = r;
} else {
/* restore p->payload to point to icmp header (cannot fail) */
if (pbuf_header(p, -(s16_t)(hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN))) {
/* restore p->payload to point to icmp header */
if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
goto icmperr;
goto memerr;
}
}
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
@@ -198,76 +187,47 @@ icmp_input(struct pbuf *p, struct netif *inp)
/* We generate an answer by switching the dest and src ip addresses,
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */
iecho = (struct icmp_echo_hdr *)p->payload;
if (pbuf_header(p, (s16_t)hlen)) {
LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Can't move over header in packet"));
} else {
err_t ret;
struct ip_hdr *iphdr = (struct ip_hdr*)p->payload;
ip4_addr_copy(iphdr->src, *src);
ip4_addr_copy(iphdr->dest, *ip4_current_src_addr());
ICMPH_TYPE_SET(iecho, ICMP_ER);
ip_addr_copy(iphdr->src, *ip_current_dest_addr());
ip_addr_copy(iphdr->dest, *ip_current_src_addr());
ICMPH_TYPE_SET(iecho, ICMP_ER);
#if CHECKSUM_GEN_ICMP
IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP) {
/* adjust the checksum */
if (iecho->chksum > PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
} else {
iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
}
}
#if LWIP_CHECKSUM_CTRL_PER_NETIF
else {
iecho->chksum = 0;
}
#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */
/* adjust the checksum */
if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
} else {
iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
}
#else /* CHECKSUM_GEN_ICMP */
iecho->chksum = 0;
iecho->chksum = 0;
#endif /* CHECKSUM_GEN_ICMP */
/* Set the correct TTL and recalculate the header checksum. */
IPH_TTL_SET(iphdr, ICMP_TTL);
IPH_CHKSUM_SET(iphdr, 0);
/* Set the correct TTL and recalculate the header checksum. */
IPH_TTL_SET(iphdr, ICMP_TTL);
IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_IP) {
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, hlen));
}
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
#endif /* CHECKSUM_GEN_IP */
ICMP_STATS_INC(icmp.xmit);
/* increase number of messages attempted to send */
MIB2_STATS_INC(mib2.icmpoutmsgs);
/* increase number of echo replies attempted to send */
MIB2_STATS_INC(mib2.icmpoutechoreps);
ICMP_STATS_INC(icmp.xmit);
/* increase number of messages attempted to send */
snmp_inc_icmpoutmsgs();
/* increase number of echo replies attempted to send */
snmp_inc_icmpoutechoreps();
/* send an ICMP packet */
ret = ip4_output_if(p, src, LWIP_IP_HDRINCL,
if(pbuf_header(p, hlen)) {
LWIP_ASSERT("Can't move over header in packet", 0);
} else {
err_t ret;
/* 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: %s\n", lwip_strerr(ret)));
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
}
}
break;
default:
if (type == ICMP_DUR) {
MIB2_STATS_INC(mib2.icmpindestunreachs);
} else if (type == ICMP_TE) {
MIB2_STATS_INC(mib2.icmpintimeexcds);
} else if (type == ICMP_PP) {
MIB2_STATS_INC(mib2.icmpinparmprobs);
} else if (type == ICMP_SQ) {
MIB2_STATS_INC(mib2.icmpinsrcquenchs);
} else if (type == ICMP_RD) {
MIB2_STATS_INC(mib2.icmpinredirects);
} else if (type == ICMP_TS) {
MIB2_STATS_INC(mib2.icmpintimestamps);
} else if (type == ICMP_TSR) {
MIB2_STATS_INC(mib2.icmpintimestampreps);
} else if (type == ICMP_AM) {
MIB2_STATS_INC(mib2.icmpinaddrmasks);
} else if (type == ICMP_AMR) {
MIB2_STATS_INC(mib2.icmpinaddrmaskreps);
}
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",
(s16_t)type, (s16_t)code));
ICMP_STATS_INC(icmp.proterr);
ICMP_STATS_INC(icmp.drop);
@@ -277,15 +237,15 @@ icmp_input(struct pbuf *p, struct netif *inp)
lenerr:
pbuf_free(p);
ICMP_STATS_INC(icmp.lenerr);
MIB2_STATS_INC(mib2.icmpinerrors);
snmp_inc_icmpinerrors();
return;
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
icmperr:
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
memerr:
pbuf_free(p);
ICMP_STATS_INC(icmp.err);
MIB2_STATS_INC(mib2.icmpinerrors);
snmp_inc_icmpinerrors();
return;
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
}
/**
@@ -300,7 +260,6 @@ icmperr:
void
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
{
MIB2_STATS_INC(mib2.icmpoutdestunreachs);
icmp_send_response(p, ICMP_DUR, t);
}
@@ -315,7 +274,6 @@ icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
void
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
{
MIB2_STATS_INC(mib2.icmpouttimeexcds);
icmp_send_response(p, ICMP_TE, t);
}
@@ -336,18 +294,13 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
struct ip_hdr *iphdr;
/* we can use the echo header here */
struct icmp_echo_hdr *icmphdr;
ip4_addr_t iphdr_src;
struct netif *netif;
/* increase number of messages attempted to send */
MIB2_STATS_INC(mib2.icmpoutmsgs);
ip_addr_t iphdr_src;
/* ICMP header + IP header + 8 bytes of data */
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
PBUF_RAM);
if (q == NULL) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
MIB2_STATS_INC(mib2.icmpouterrors);
return;
}
LWIP_ASSERT("check that first pbuf can hold icmp message",
@@ -355,9 +308,9 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
iphdr = (struct ip_hdr *)p->payload;
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->src);
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
LWIP_DEBUGF(ICMP_DEBUG, (" to "));
ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->dest);
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
icmphdr = (struct icmp_echo_hdr *)q->payload;
@@ -370,28 +323,17 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
ip4_addr_copy(iphdr_src, iphdr->src);
#ifdef LWIP_HOOK_IP4_ROUTE_SRC
{
ip4_addr_t iphdr_dst;
ip4_addr_copy(iphdr_dst, iphdr->dest);
netif = ip4_route_src(&iphdr_src, &iphdr_dst);
}
#else
netif = ip4_route(&iphdr_src);
#endif
if (netif != NULL) {
/* calculate checksum */
icmphdr->chksum = 0;
#if CHECKSUM_GEN_ICMP
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP) {
icmphdr->chksum = inet_chksum(icmphdr, q->len);
}
#endif
ICMP_STATS_INC(icmp.xmit);
ip4_output_if(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP, netif);
}
/* calculate checksum */
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_addr_copy(iphdr_src, iphdr->src);
ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);
pbuf_free(q);
}
#endif /* LWIP_IPV4 && LWIP_ICMP */
#endif /* LWIP_ICMP */

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,13 @@
/**
* @file
* This file is a posix wrapper for lwip/netdb.h.
* Functions common to all TCP/IPv4 modules, such as the byte order functions.
*
*/
/*
* 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:
*
@@ -28,6 +32,11 @@
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/netdb.h"
#include "lwip/opt.h"
#include "lwip/inet.h"

View File

@@ -1,16 +1,7 @@
/**
* @file
* Incluse internet checksum functions.\n
* Incluse internet checksum functions.
*
* These are some reference implementations of the checksum algorithm, with the
* aim of being simple, correct and fully portable. Checksumming is the
* first thing you would want to optimize for your platform. If you create
* your own version, link it in and in your cc.h put:
*
* \#define LWIP_CHKSUM your_checksum_routine
*
* Or you can select from the implementations below by defining
* LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
*/
/*
@@ -49,16 +40,26 @@
#include "lwip/inet_chksum.h"
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#include <stddef.h>
#include <string.h>
/* These are some reference implementations of the checksum algorithm, with the
* aim of being simple, correct and fully portable. Checksumming is the
* first thing you would want to optimize for your platform. If you create
* your own version, link it in and in your cc.h put:
*
* #define LWIP_CHKSUM <your_checksum_routine>
*
* Or you can select from the implementations below by defining
* LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
*/
#ifndef LWIP_CHKSUM
# define LWIP_CHKSUM lwip_standard_chksum
# ifndef LWIP_CHKSUM_ALGORITHM
# define LWIP_CHKSUM_ALGORITHM 2
# endif
u16_t lwip_standard_chksum(const void *dataptr, int len);
#endif
/* If none set: */
#ifndef LWIP_CHKSUM_ALGORITHM
@@ -71,21 +72,21 @@ u16_t lwip_standard_chksum(const void *dataptr, int len);
*
* @param dataptr points to start of data to be summed at any boundary
* @param len length of data to be summed
* @return host order (!) lwip checksum (non-inverted Internet sum)
* @return host order (!) lwip checksum (non-inverted Internet sum)
*
* @note accumulator size limits summable length to 64k
* @note host endianess is irrelevant (p3 RFC1071)
*/
u16_t
lwip_standard_chksum(const void *dataptr, int len)
static u16_t
lwip_standard_chksum(void *dataptr, u16_t len)
{
u32_t acc;
u16_t src;
const u8_t *octetptr;
u8_t *octetptr;
acc = 0;
/* dataptr may be at odd or even addresses */
octetptr = (const u8_t*)dataptr;
octetptr = (u8_t*)dataptr;
while (len > 1) {
/* declare first octet as most significant
thus assume network order, ignoring host order */
@@ -107,10 +108,10 @@ lwip_standard_chksum(const void *dataptr, int len)
if ((acc & 0xffff0000UL) != 0) {
acc = (acc >> 16) + (acc & 0x0000ffffUL);
}
/* This maybe a little confusing: reorder sum using lwip_htons()
instead of lwip_ntohs() since it has a little less call overhead.
/* This maybe a little confusing: reorder sum using htons()
instead of ntohs() since it has a little less call overhead.
The caller must invert bits for Internet sum ! */
return lwip_htons((u16_t)acc);
return htons((u16_t)acc);
}
#endif
@@ -127,14 +128,14 @@ lwip_standard_chksum(const void *dataptr, int len)
*
* @param dataptr points to start of data to be summed at any boundary
* @param len length of data to be summed
* @return host order (!) lwip checksum (non-inverted Internet sum)
* @return host order (!) lwip checksum (non-inverted Internet sum)
*/
u16_t
lwip_standard_chksum(const void *dataptr, int len)
static u16_t
lwip_standard_chksum(void *dataptr, int len)
{
const u8_t *pb = (const u8_t *)dataptr;
const u16_t *ps;
u16_t t = 0;
u8_t *pb = (u8_t *)dataptr;
u16_t *ps, t = 0;
u32_t sum = 0;
int odd = ((mem_ptr_t)pb & 1);
@@ -145,7 +146,7 @@ lwip_standard_chksum(const void *dataptr, int len)
}
/* Add the bulk of the data */
ps = (const u16_t *)(const void *)pb;
ps = (u16_t *)(void *)pb;
while (len > 1) {
sum += *ps++;
len -= 2;
@@ -153,14 +154,14 @@ lwip_standard_chksum(const void *dataptr, int len)
/* Consume left-over byte, if any */
if (len > 0) {
((u8_t *)&t)[0] = *(const u8_t *)ps;
((u8_t *)&t)[0] = *(u8_t *)ps;
}
/* Add end bytes */
sum += t;
/* Fold 32-bit sum to 16 bits
calling this twice is probably faster than if statements... */
calling this twice is propably faster than if statements... */
sum = FOLD_U32T(sum);
sum = FOLD_U32T(sum);
@@ -177,21 +178,21 @@ lwip_standard_chksum(const void *dataptr, int len)
/**
* An optimized checksum routine. Basically, it uses loop-unrolling on
* the checksum loop, treating the head and tail bytes specially, whereas
* the inner loop acts on 8 bytes at a time.
* the inner loop acts on 8 bytes at a time.
*
* @arg start of buffer to be checksummed. May be an odd byte address.
* @len number of bytes in the buffer to be checksummed.
* @return host order (!) lwip checksum (non-inverted Internet sum)
*
* @return host order (!) lwip checksum (non-inverted Internet sum)
*
* by Curt McDowell, Broadcom Corp. December 8th, 2005
*/
u16_t
lwip_standard_chksum(const void *dataptr, int len)
static u16_t
lwip_standard_chksum(void *dataptr, int len)
{
const u8_t *pb = (const u8_t *)dataptr;
const u16_t *ps;
u16_t t = 0;
const u32_t *pl;
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 = ((mem_ptr_t)pb & 1);
@@ -201,14 +202,14 @@ lwip_standard_chksum(const void *dataptr, int len)
len--;
}
ps = (const u16_t *)(const void*)pb;
ps = (u16_t *)pb;
if (((mem_ptr_t)ps & 3) && len > 1) {
sum += *ps++;
len -= 2;
}
pl = (const u32_t *)(const void*)ps;
pl = (u32_t *)ps;
while (len > 7) {
tmp = sum + *pl++; /* ping */
@@ -227,7 +228,7 @@ lwip_standard_chksum(const void *dataptr, int len)
/* make room in upper bits */
sum = FOLD_U32T(sum);
ps = (const u16_t *)pl;
ps = (u16_t *)pl;
/* 16-bit aligned word remaining? */
while (len > 1) {
@@ -237,13 +238,13 @@ lwip_standard_chksum(const void *dataptr, int len)
/* dangling tail byte remaining? */
if (len > 0) { /* include odd byte */
((u8_t *)&t)[0] = *(const u8_t *)ps;
((u8_t *)&t)[0] = *(u8_t *)ps;
}
sum += t; /* add end bytes */
/* Fold 32-bit sum to 16 bits
calling this twice is probably faster than if statements... */
calling this twice is propably faster than if statements... */
sum = FOLD_U32T(sum);
sum = FOLD_U32T(sum);
@@ -255,15 +256,32 @@ lwip_standard_chksum(const void *dataptr, int len)
}
#endif
/** 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)
/* 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,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len)
{
u32_t acc;
u32_t addr;
struct pbuf *q;
u8_t swapped = 0;
u8_t swapped;
acc = 0;
swapped = 0;
/* iterate through all pbuf in chain */
for (q = p; q != NULL; q = q->next) {
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);
@@ -281,22 +299,26 @@ inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc)
if (swapped) {
acc = SWAP_BYTES_IN_WORD(acc);
}
acc += (u32_t)lwip_htons((u16_t)proto);
acc += (u32_t)lwip_htons(proto_len);
addr = ip4_addr_get_u32(src);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = ip4_addr_get_u32(dest);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
acc += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
/* Fold 32-bit sum to 16 bits
calling this twice is probably faster than if statements... */
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);
}
#if LWIP_IPV4
/* inet_chksum_pseudo:
*
* Calculates the IPv4 pseudo Internet checksum used by TCP and UDP for a pbuf chain.
* 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)
@@ -307,104 +329,20 @@ inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc)
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
const ip4_addr_t *src, const ip4_addr_t *dest)
inet_chksum_pseudo_partial(struct pbuf *p,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len, u16_t chksum_len)
{
u32_t acc;
u32_t addr;
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);
}
#endif /* LWIP_IPV4 */
#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 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 src source ipv6 address (used for checksum of pseudo header)
* @param dest destination ipv6 address (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,
const ip6_addr_t *src, const 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 */
/* ip_chksum_pseudo:
*
* Calculates the IPv4 or IPv6 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
ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
const ip_addr_t *src, const ip_addr_t *dest)
{
#if LWIP_IPV6
if (IP_IS_V6(dest)) {
return ip6_chksum_pseudo(p, proto, proto_len, ip_2_ip6(src), ip_2_ip6(dest));
}
#endif /* LWIP_IPV6 */
#if LWIP_IPV4 && LWIP_IPV6
else
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if LWIP_IPV4
{
return inet_chksum_pseudo(p, proto, proto_len, ip_2_ip4(src), ip_2_ip4(dest));
}
#endif /* LWIP_IPV4 */
}
/** 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 = 0;
u8_t swapped;
u16_t chklen;
acc = 0;
swapped = 0;
/* iterate through all pbuf in chain */
for (q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
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",
(void *)q, (void *)q->next));
chklen = q->len;
@@ -427,118 +365,21 @@ inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len,
if (swapped) {
acc = SWAP_BYTES_IN_WORD(acc);
}
acc += (u32_t)lwip_htons((u16_t)proto);
acc += (u32_t)lwip_htons(proto_len);
/* Fold 32-bit sum to 16 bits
calling this twice is probably 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);
}
#if LWIP_IPV4
/* inet_chksum_pseudo_partial:
*
* Calculates the IPv4 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, const ip4_addr_t *src, const ip4_addr_t *dest)
{
u32_t acc;
u32_t addr;
addr = ip4_addr_get_u32(src);
acc = (addr & 0xffffUL);
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 += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
/* Fold 32-bit sum to 16 bits
calling this twice is propably faster than if statements... */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc);
}
#endif /* LWIP_IPV4 */
#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 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
* @param src source ipv6 address (used for checksum of pseudo header)
* @param dest destination ipv6 address (used for checksum of pseudo header)
* @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, const ip6_addr_t *src, const 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 */
/* ip_chksum_pseudo_partial:
*
* Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain.
*
* @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
ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
u16_t chksum_len, const ip_addr_t *src, const ip_addr_t *dest)
{
#if LWIP_IPV6
if (IP_IS_V6(dest)) {
return ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip6(src), ip_2_ip6(dest));
}
#endif /* LWIP_IPV6 */
#if LWIP_IPV4 && LWIP_IPV6
else
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if LWIP_IPV4
{
return inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip4(src), ip_2_ip4(dest));
}
#endif /* LWIP_IPV4 */
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
return (u16_t)~(acc & 0xffffUL);
}
/* inet_chksum:
@@ -552,9 +393,9 @@ ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
*/
u16_t
inet_chksum(const void *dataptr, u16_t len)
inet_chksum(void *dataptr, u16_t len)
{
return (u16_t)~(unsigned int)LWIP_CHKSUM(dataptr, len);
return ~LWIP_CHKSUM(dataptr, len);
}
/**
@@ -573,7 +414,7 @@ inet_chksum_pbuf(struct pbuf *p)
acc = 0;
swapped = 0;
for (q = p; q != NULL; q = q->next) {
for(q = p; q != NULL; q = q->next) {
acc += LWIP_CHKSUM(q->payload, q->len);
acc = FOLD_U32T(acc);
if (q->len % 2 != 0) {

File diff suppressed because it is too large Load Diff

View File

@@ -6,9 +6,9 @@
/*
* 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,47 +17,44 @@
* 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"
#if LWIP_IPV4
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
/* used by IP4_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
const ip_addr_t ip_addr_any = IPADDR4_INIT(IPADDR_ANY);
const ip_addr_t ip_addr_broadcast = IPADDR4_INIT(IPADDR_BROADCAST);
/* 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
*
* 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(u32_t addr, const struct netif *netif)
ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)
{
ip4_addr_t ipaddr;
ip_addr_t ipaddr;
ip4_addr_set_u32(&ipaddr, addr);
/* all ones (broadcast) or all zeroes (old skool broadcast) */
@@ -70,13 +67,13 @@ ip4_addr_isbroadcast_u32(u32_t addr, const struct netif *netif)
* 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_ip4_addr(netif))) {
} else if (addr == ip4_addr_get_u32(&netif->ip_addr)) {
return 0;
/* on the same (sub) network... */
} else if (ip4_addr_netcmp(&ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif))
} else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))
/* ...and host identifier bits are all ones? =>... */
&& ((addr & ~ip4_addr_get_u32(netif_ip4_netmask(netif))) ==
(IPADDR_BROADCAST & ~ip4_addr_get_u32(netif_ip4_netmask(netif))))) {
&& ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==
(IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {
/* => network broadcast address */
return 1;
} else {
@@ -126,15 +123,15 @@ ip4_addr_netmask_valid(u32_t netmask)
* Ascii internet address interpretation routine.
* The value returned is in network order.
*
* @param cp IP address in ascii representation (e.g. "127.0.0.1")
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
* @return ip address in network order
*/
u32_t
ipaddr_addr(const char *cp)
{
ip4_addr_t val;
ip_addr_t val;
if (ip4addr_aton(cp, &val)) {
if (ipaddr_aton(cp, &val)) {
return ip4_addr_get_u32(&val);
}
return (IPADDR_NONE);
@@ -147,12 +144,12 @@ ipaddr_addr(const char *cp)
* This replaces inet_addr, the return value from which
* cannot distinguish between failure and a local broadcast address.
*
* @param cp IP address in ascii representation (e.g. "127.0.0.1")
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
* @param addr pointer to which to save the ip address in network order
* @return 1 if cp could be converted to addr, 0 on failure
*/
int
ip4addr_aton(const char *cp, ip4_addr_t *addr)
ipaddr_aton(const char *cp, ip_addr_t *addr)
{
u32_t val;
u8_t base;
@@ -167,9 +164,8 @@ ip4addr_aton(const char *cp, ip4_addr_t *addr)
* Values are specified as for C:
* 0x=hex, 0=octal, 1-9=decimal.
*/
if (!isdigit(c)) {
return 0;
}
if (!isdigit(c))
return (0);
val = 0;
base = 10;
if (c == '0') {
@@ -177,20 +173,18 @@ ip4addr_aton(const char *cp, ip4_addr_t *addr)
if (c == 'x' || c == 'X') {
base = 16;
c = *++cp;
} else {
} else
base = 8;
}
}
for (;;) {
if (isdigit(c)) {
val = (val * base) + (u32_t)(c - '0');
val = (val * base) + (int)(c - '0');
c = *++cp;
} else if (base == 16 && isxdigit(c)) {
val = (val << 4) | (u32_t)(c + 10 - (islower(c) ? 'a' : 'A'));
val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
c = *++cp;
} else {
} else
break;
}
}
if (c == '.') {
/*
@@ -200,19 +194,18 @@ ip4addr_aton(const char *cp, ip4_addr_t *addr)
* a.b (with b treated as 24 bits)
*/
if (pp >= parts + 3) {
return 0;
return (0);
}
*pp++ = val;
c = *++cp;
} else {
} else
break;
}
}
/*
* Check for trailing characters.
*/
if (c != '\0' && !isspace(c)) {
return 0;
return (0);
}
/*
* Concoct the address according to
@@ -221,37 +214,28 @@ ip4addr_aton(const char *cp, ip4_addr_t *addr)
switch (pp - parts + 1) {
case 0:
return 0; /* initial nondigit */
return (0); /* initial nondigit */
case 1: /* a -- 32 bits */
break;
case 2: /* a.b -- 8.24 bits */
if (val > 0xffffffUL) {
return 0;
}
if (parts[0] > 0xff) {
return 0;
return (0);
}
val |= parts[0] << 24;
break;
case 3: /* a.b.c -- 8.8.16 bits */
if (val > 0xffff) {
return 0;
}
if ((parts[0] > 0xff) || (parts[1] > 0xff)) {
return 0;
return (0);
}
val |= (parts[0] << 24) | (parts[1] << 16);
break;
case 4: /* a.b.c.d -- 8.8.8.8 bits */
if (val > 0xff) {
return 0;
}
if ((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) {
return 0;
return (0);
}
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
break;
@@ -260,9 +244,9 @@ ip4addr_aton(const char *cp, ip4_addr_t *addr)
break;
}
if (addr) {
ip4_addr_set_u32(addr, lwip_htonl(val));
ip4_addr_set_u32(addr, htonl(val));
}
return 1;
return (1);
}
/**
@@ -271,13 +255,13 @@ ip4addr_aton(const char *cp, ip4_addr_t *addr)
*
* @param addr ip address in network order to convert
* @return pointer to a global static (!) buffer that holds the ASCII
* representation of addr
* represenation of addr
*/
char*
ip4addr_ntoa(const ip4_addr_t *addr)
char *
ipaddr_ntoa(const ip_addr_t *addr)
{
static char str[IP4ADDR_STRLEN_MAX];
return ip4addr_ntoa_r(addr, str, IP4ADDR_STRLEN_MAX);
static char str[16];
return ipaddr_ntoa_r(addr, str, 16);
}
/**
@@ -289,8 +273,7 @@ ip4addr_ntoa(const ip4_addr_t *addr)
* @return either pointer to buf which now holds the ASCII
* representation of addr or NULL if buf was too small
*/
char*
ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen)
char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
{
u32_t s_addr;
char inv[3];
@@ -305,14 +288,14 @@ ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen)
rp = buf;
ap = (u8_t *)&s_addr;
for (n = 0; n < 4; n++) {
for(n = 0; n < 4; n++) {
i = 0;
do {
rem = *ap % (u8_t)10;
*ap /= (u8_t)10;
inv[i++] = (char)('0' + rem);
} while (*ap);
while (i--) {
inv[i++] = '0' + rem;
} while(*ap);
while(i--) {
if (len++ >= buflen) {
return NULL;
}
@@ -327,5 +310,3 @@ ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen)
*--rp = 0;
return buf;
}
#endif /* LWIP_IPV4 */

View File

@@ -6,9 +6,9 @@
/*
* 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,35 +17,33 @@
* 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: Jani Monoses <jani@iv.ro>
*
* Author: Jani Monoses <jani@iv.ro>
* Simon Goldschmidt
* original reassembly code by Adam Dunkels <adam@sics.se>
*
*
*/
#include "lwip/opt.h"
#if LWIP_IPV4
#include "lwip/ip4_frag.h"
#include "lwip/ip_frag.h"
#include "lwip/def.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/snmp.h"
#include "lwip/stats.h"
#include "lwip/icmp.h"
@@ -102,8 +100,8 @@ PACK_STRUCT_END
#endif
#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
(ip4_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
ip4_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
(ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
/* global variables */
@@ -160,7 +158,7 @@ static int
ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
{
u16_t pbufs_freed = 0;
u16_t clen;
u8_t clen;
struct pbuf *p;
struct ip_reass_helper *iprh;
@@ -169,7 +167,7 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p
LWIP_ASSERT("prev->next == ipr", prev->next == ipr);
}
MIB2_STATS_INC(mib2.ipreasmfails);
snmp_inc_ipreasmfails();
#if LWIP_ICMP
iprh = (struct ip_reass_helper *)ipr->p->payload;
if (iprh->start == 0) {
@@ -187,7 +185,7 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p
}
#endif /* LWIP_ICMP */
/* First, free all received pbufs. The individual pbufs need to be released
/* 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) {
@@ -225,7 +223,7 @@ ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
/* @todo Can't we simply remove the last datagram in the
* linked list behind reassdatagrams?
*/
struct ip_reassdata *r, *oldest, *prev, *oldest_prev;
struct ip_reassdata *r, *oldest, *prev;
int pbufs_freed = 0, pbufs_freed_current;
int other_datagrams;
@@ -234,7 +232,6 @@ ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
do {
oldest = NULL;
prev = NULL;
oldest_prev = NULL;
other_datagrams = 0;
r = reassdatagrams;
while (r != NULL) {
@@ -243,11 +240,9 @@ ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
other_datagrams++;
if (oldest == NULL) {
oldest = r;
oldest_prev = prev;
} else if (r->timer <= oldest->timer) {
/* older than the previous oldest */
oldest = r;
oldest_prev = prev;
}
}
if (r->next != NULL) {
@@ -256,7 +251,7 @@ ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
r = r->next;
}
if (oldest != NULL) {
pbufs_freed_current = ip_reass_free_complete_datagram(oldest, oldest_prev);
pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);
pbufs_freed += pbufs_freed_current;
}
} while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
@@ -274,10 +269,6 @@ static struct ip_reassdata*
ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
{
struct ip_reassdata* ipr;
#if ! IP_REASS_FREE_OLDEST
LWIP_UNUSED_ARG(clen);
#endif
/* No matching previous fragment found, allocate a new reassdata struct */
ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
if (ipr == NULL) {
@@ -312,6 +303,7 @@ ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
static void
ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
{
/* dequeue the reass struct */
if (reassdatagrams == ipr) {
/* it was the first in the list */
@@ -322,7 +314,7 @@ ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
prev->next = ipr->next;
}
/* now we can free the ip_reassdata struct */
/* now we can free the ip_reass struct */
memp_free(MEMP_REASSDATA, ipr);
}
@@ -331,7 +323,7 @@ ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
* will grow over time as new pbufs are rx.
* Also checks that the datagram passes basic continuity checks (if the last
* fragment was received at least once).
* @param ipr points to the reassembly state
* @param root_p points to the 'root' pbuf for the current datagram being assembled.
* @param new_p points to the pbuf for the current fragment
* @return 0 if invalid, >0 otherwise
*/
@@ -340,14 +332,14 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct
{
struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
struct pbuf *q;
u16_t offset, len;
u16_t offset,len;
struct ip_hdr *fraghdr;
int valid = 1;
/* Extract length and fragment offset from current fragment */
fraghdr = (struct ip_hdr*)new_p->payload;
len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
fraghdr = (struct ip_hdr*)new_p->payload;
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
/* overwrite the fragment's ip header from the pbuf with our helper struct,
* and setup the embedded helper structure. */
@@ -360,7 +352,7 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct
iprh->end = offset + len;
/* Iterate through until we either get to the end of the list (append),
* or we find one with a larger offset (insert). */
* or we find on with a larger offset (insert). */
for (q = ipr->p; q != NULL;) {
iprh_tmp = (struct ip_reass_helper*)q->payload;
if (iprh->start < iprh_tmp->start) {
@@ -380,16 +372,16 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct
ipr->p = new_p;
}
break;
} else if (iprh->start == iprh_tmp->start) {
} else if(iprh->start == iprh_tmp->start) {
/* received the same datagram twice: no need to keep the datagram */
goto freepbuf;
#if IP_REASS_CHECK_OVERLAP
} else if (iprh->start < iprh_tmp->end) {
} else if(iprh->start < iprh_tmp->end) {
/* overlap: no need to keep the new datagram */
goto freepbuf;
#endif /* IP_REASS_CHECK_OVERLAP */
} else {
/* Check if the fragments received so far have no holes. */
/* Check if the fragments received so far have no wholes. */
if (iprh_prev != NULL) {
if (iprh_prev->end != iprh_tmp->start) {
/* There is a fragment missing between the current
@@ -427,14 +419,14 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct
/* At this point, the validation part begins: */
/* If we already received the last fragment */
if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
/* and had no holes so far */
/* and had no wholes so far */
if (valid) {
/* then check if the rest of the fragments is here */
/* Check if the queue starts with the first datagram */
if ((ipr->p == NULL) || (((struct ip_reass_helper*)ipr->p->payload)->start != 0)) {
if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {
valid = 0;
} else {
/* and check that there are no holes after this datagram */
/* and check that there are no wholes after this datagram */
iprh_prev = iprh;
q = iprh->next_pbuf;
while (q != NULL) {
@@ -481,27 +473,29 @@ freepbuf:
* @return NULL if reassembly is incomplete, ? otherwise
*/
struct pbuf *
ip4_reass(struct pbuf *p)
ip_reass(struct pbuf *p)
{
struct pbuf *r;
struct ip_hdr *fraghdr;
struct ip_reassdata *ipr;
struct ip_reass_helper *iprh;
u16_t offset, len, clen;
u16_t offset, len;
u8_t clen;
struct ip_reassdata *ipr_prev = NULL;
IPFRAG_STATS_INC(ip_frag.recv);
MIB2_STATS_INC(mib2.ipreasmreqds);
snmp_inc_ipreasmreqds();
fraghdr = (struct ip_hdr*)p->payload;
if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: IP options currently not supported!\n"));
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));
IPFRAG_STATS_INC(ip_frag.err);
goto nullreturn;
}
offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
/* Check if we are allowed to enqueue more datagrams. */
clen = pbuf_clen(p);
@@ -512,7 +506,7 @@ ip4_reass(struct pbuf *p)
#endif /* IP_REASS_FREE_OLDEST */
{
/* No datagram could be freed and still too many pbufs enqueued */
LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
IPFRAG_STATS_INC(ip_frag.memerr);
/* @todo: send ICMP time exceeded here? */
@@ -528,23 +522,24 @@ ip4_reass(struct pbuf *p)
in the reassembly buffer. If so, we proceed with copying the
fragment into the buffer. */
if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: matching previous fragment ID=%"X16_F"\n",
lwip_ntohs(IPH_ID(fraghdr))));
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
ntohs(IPH_ID(fraghdr))));
IPFRAG_STATS_INC(ip_frag.cachehit);
break;
}
ipr_prev = ipr;
}
if (ipr == NULL) {
/* Enqueue a new datagram into the datagram queue */
ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
/* Bail if unable to enqueue */
if (ipr == NULL) {
if(ipr == NULL) {
goto nullreturn;
}
} else {
if (((lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
((lwip_ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
/* ipr->iphdr is not the header from the first fragment, but fraghdr is
* -> copy fraghdr into ipr->iphdr since we want to have the header
* of the first fragment (for ICMP time exceeded and later, for copying
@@ -552,11 +547,11 @@ ip4_reass(struct pbuf *p)
SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
}
}
/* Track the current number of pbufs current 'in-flight', in order to limit
/* 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 */
ip_reass_pbufcount += clen;
/* At this point, we have either created a new entry or pointing
/* At this point, we have either created a new entry or pointing
* to an existing one */
/* check for 'no more fragments', and update queue entry*/
@@ -564,13 +559,12 @@ ip4_reass(struct pbuf *p)
ipr->flags |= IP_REASS_FLAG_LASTFRAG;
ipr->datagram_len = offset + len;
LWIP_DEBUGF(IP_REASS_DEBUG,
("ip4_reass: last fragment seen, total len %"S16_F"\n",
("ip_reass: last fragment seen, total len %"S16_F"\n",
ipr->datagram_len));
}
/* find the right place to insert this pbuf */
/* @todo: trim pbufs if fragments are overlapping */
if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
struct ip_reassdata *ipr_prev;
/* the totally last fragment (flag more fragments = 0) was received at least
* once AND all fragments are received */
ipr->datagram_len += IP_HLEN;
@@ -581,47 +575,29 @@ ip4_reass(struct pbuf *p)
/* copy the original ip header back to the first pbuf */
fraghdr = (struct ip_hdr*)(ipr->p->payload);
SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
IPH_LEN_SET(fraghdr, lwip_htons(ipr->datagram_len));
IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
IPH_OFFSET_SET(fraghdr, 0);
IPH_CHKSUM_SET(fraghdr, 0);
/* @todo: do we need to set/calculate the correct checksum? */
#if CHECKSUM_GEN_IP
IF__NETIF_CHECKSUM_ENABLED(ip_current_input_netif(), NETIF_CHECKSUM_GEN_IP) {
IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
}
#endif /* CHECKSUM_GEN_IP */
/* @todo: do we need to set calculate the correct checksum? */
IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
p = ipr->p;
/* chain together the pbufs contained within the reass_data list. */
while (r != NULL) {
while(r != NULL) {
iprh = (struct ip_reass_helper*)r->payload;
/* hide the ip header for every succeeding fragment */
/* hide the ip header for every succeding fragment */
pbuf_header(r, -IP_HLEN);
pbuf_cat(p, r);
r = iprh->next_pbuf;
}
/* find the previous entry in the linked list */
if (ipr == reassdatagrams) {
ipr_prev = NULL;
} else {
for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) {
if (ipr_prev->next == ipr) {
break;
}
}
}
/* release the sources allocate for the fragment queue entry */
ip_reass_dequeue_datagram(ipr, ipr_prev);
/* and adjust the number of pbufs currently queued for reassembly. */
ip_reass_pbufcount -= pbuf_clen(p);
MIB2_STATS_INC(mib2.ipreasmoks);
/* Return the pbuf chain */
return p;
}
@@ -630,7 +606,7 @@ ip4_reass(struct pbuf *p)
return NULL;
nullreturn:
LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: nullreturn\n"));
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));
IPFRAG_STATS_INC(ip_frag.drop);
pbuf_free(p);
return NULL;
@@ -638,6 +614,10 @@ nullreturn:
#endif /* IP_REASSEMBLY */
#if IP_FRAG
#if IP_FRAG_USES_STATIC_BUF
static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
#else /* IP_FRAG_USES_STATIC_BUF */
#if !LWIP_NETIF_TX_SINGLE_PBUF
/** Allocate a new struct pbuf_custom_ref */
static struct pbuf_custom_ref*
@@ -668,12 +648,14 @@ ipfrag_free_pbuf_custom(struct pbuf *p)
ip_frag_free_pbuf_custom_ref(pcr);
}
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
#endif /* IP_FRAG_USES_STATIC_BUF */
/**
* Fragment an IP datagram if too large for the netif.
*
* Chop the datagram in MTU sized chunks and send them in order
* by pointing PBUF_REFs into p.
* by using a fixed size static memory buffer (PBUF_REF) or
* point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
*
* @param p ip packet to send
* @param netif the netif on which to send
@@ -681,55 +663,93 @@ ipfrag_free_pbuf_custom(struct pbuf *p)
*
* @return ERR_OK if sent successfully, err_t otherwise
*/
err_t
ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
err_t
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;
u16_t nfb;
u16_t left, cop;
u16_t mtu = netif->mtu;
u16_t ofo, omf;
u16_t last;
u16_t poff = IP_HLEN;
u16_t tmp;
#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
u16_t newpbuflen = 0;
u16_t left_to_copy;
#endif
struct ip_hdr *original_iphdr;
struct ip_hdr *iphdr;
const u16_t nfb = (netif->mtu - IP_HLEN) / 8;
u16_t left, fragsize;
u16_t ofo;
int last;
u16_t poff = IP_HLEN;
u16_t tmp;
/* Get a RAM based MTU sized pbuf */
#if IP_FRAG_USES_STATIC_BUF
/* When using a static buffer, we use a PBUF_REF, which we will
* use to reference the packet (without link header).
* Layer and length is irrelevant.
*/
rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
if (rambuf == NULL) {
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
return ERR_MEM;
}
rambuf->tot_len = rambuf->len = mtu;
rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
/* Copy the IP header in it */
iphdr = (struct ip_hdr *)rambuf->payload;
SMEMCPY(iphdr, p->payload, IP_HLEN);
#else /* IP_FRAG_USES_STATIC_BUF */
original_iphdr = (struct ip_hdr *)p->payload;
iphdr = original_iphdr;
LWIP_ERROR("ip4_frag() does not support IP options", IPH_HL(iphdr) * 4 == IP_HLEN, return ERR_VAL);
#endif /* IP_FRAG_USES_STATIC_BUF */
/* Save original offset */
tmp = lwip_ntohs(IPH_OFFSET(iphdr));
tmp = ntohs(IPH_OFFSET(iphdr));
ofo = tmp & IP_OFFMASK;
LWIP_ERROR("ip_frag(): MF already set", (tmp & IP_MF) == 0, return ERR_VAL);
omf = tmp & IP_MF;
left = p->tot_len - IP_HLEN;
while (left) {
/* Fill this fragment */
fragsize = LWIP_MIN(left, nfb * 8);
nfb = (mtu - IP_HLEN) / 8;
while (left) {
last = (left <= mtu - IP_HLEN);
/* Set new offset and MF flag */
tmp = omf | (IP_OFFMASK & (ofo));
if (!last) {
tmp = tmp | IP_MF;
}
/* Fill this fragment */
cop = last ? left : nfb * 8;
#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, fragsize, PBUF_RAM);
rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);
if (rambuf == NULL) {
goto memerr;
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, fragsize, poff);
poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);
/* make room for the IP header */
if (pbuf_header(rambuf, IP_HLEN)) {
if(pbuf_header(rambuf, IP_HLEN)) {
pbuf_free(rambuf);
goto memerr;
return ERR_MEM;
}
/* fill in the IP header */
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
iphdr = (struct ip_hdr*)rambuf->payload;
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.
@@ -738,36 +758,37 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
*/
rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
if (rambuf == NULL) {
goto memerr;
return ERR_MEM;
}
LWIP_ASSERT("this needs a pbuf in one piece!",
(p->len >= (IP_HLEN)));
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
iphdr = (struct ip_hdr *)rambuf->payload;
left_to_copy = fragsize;
/* Can just adjust p directly for needed offset. */
p->payload = (u8_t *)p->payload + poff;
p->len -= poff;
left_to_copy = cop;
while (left_to_copy) {
struct pbuf_custom_ref *pcr;
u16_t plen = p->len - poff;
newpbuflen = LWIP_MIN(left_to_copy, plen);
newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
/* Is this pbuf already empty? */
if (!newpbuflen) {
poff = 0;
p = p->next;
continue;
}
pcr = ip_frag_alloc_pbuf_custom_ref();
if (pcr == NULL) {
pbuf_free(rambuf);
goto 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,
(u8_t*)p->payload + poff, 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);
goto memerr;
return ERR_MEM;
}
pbuf_ref(p);
pcr->original = p;
@@ -779,30 +800,42 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
pbuf_cat(rambuf, newpbuf);
left_to_copy -= newpbuflen;
if (left_to_copy) {
poff = 0;
p = p->next;
}
}
poff += newpbuflen;
poff = newpbuflen;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
#endif /* IP_FRAG_USES_STATIC_BUF */
/* Correct header */
last = (left <= netif->mtu - IP_HLEN);
/* Set new offset and MF flag */
tmp = (IP_OFFMASK & (ofo));
if (!last) {
tmp = tmp | IP_MF;
}
IPH_OFFSET_SET(iphdr, lwip_htons(tmp));
IPH_LEN_SET(iphdr, lwip_htons(fragsize + IP_HLEN));
IPH_OFFSET_SET(iphdr, htons(tmp));
IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) {
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
}
#endif /* CHECKSUM_GEN_IP */
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
#if IP_FRAG_USES_STATIC_BUF
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
* free it.A PBUF_ROM style pbuf for which pbuf_header
* worked would make things simpler.
*/
header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
if (header != NULL) {
pbuf_chain(header, rambuf);
netif->output(netif, header, dest);
IPFRAG_STATS_INC(ip_frag.xmit);
snmp_inc_ipfragcreates();
pbuf_free(header);
} else {
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
pbuf_free(rambuf);
return ERR_MEM;
}
#else /* IP_FRAG_USES_STATIC_BUF */
/* No need for separate header pbuf - we allowed room for it in rambuf
* when allocated.
*/
@@ -815,17 +848,16 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
* will have already sent the packet, the free will really free, and
* there will be zero memory penalty.
*/
pbuf_free(rambuf);
left -= fragsize;
#endif /* IP_FRAG_USES_STATIC_BUF */
left -= cop;
ofo += nfb;
}
MIB2_STATS_INC(mib2.ipfragoks);
#if IP_FRAG_USES_STATIC_BUF
pbuf_free(rambuf);
#endif /* IP_FRAG_USES_STATIC_BUF */
snmp_inc_ipfragoks();
return ERR_OK;
memerr:
MIB2_STATS_INC(mib2.ipfragfails);
return ERR_MEM;
}
#endif /* IP_FRAG */
#endif /* LWIP_IPV4 */

1
src/core/ipv6/README Normal file
View File

@@ -0,0 +1 @@
IPv6 support in lwIP is very experimental.

View File

@@ -1,50 +0,0 @@
/**
* @file
*
* DHCPv6.
*/
/*
* 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_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip6_addr.h"
#include "lwip/def.h"
#endif /* LWIP_IPV6 && LWIP_IPV6_DHCP6 */

View File

@@ -1,118 +0,0 @@
/**
* @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 "lwip/prot/ethernet.h"
#include "netif/ethernet.h"
#include <string.h>
/**
* 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, ask the ND6 module what to do. It will either let us
* send the the packet right away, or queue the packet for later itself, unless
* an error occurs.
*
* @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_OK or the return value of @ref nd6_get_next_hop_addr_or_queue.
*/
err_t
ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
{
struct eth_addr dest;
const u8_t *hwaddr;
err_t result;
/* 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] = ((const u8_t *)(&(ip6addr->addr[3])))[0];
dest.addr[3] = ((const u8_t *)(&(ip6addr->addr[3])))[1];
dest.addr[4] = ((const u8_t *)(&(ip6addr->addr[3])))[2];
dest.addr[5] = ((const u8_t *)(&(ip6addr->addr[3])))[3];
/* Send out. */
return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
}
/* We have a unicast destination IP address */
/* @todo anycast? */
/* Ask ND6 what to do with the packet. */
result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr);
if (result != ERR_OK) {
return result;
}
/* If no hardware address is returned, nd6 has queued the packet for later. */
if (hwaddr == NULL) {
return ERR_OK;
}
/* Send out the packet using the returned hardware address. */
SMEMCPY(dest.addr, hwaddr, 6);
return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
}
#endif /* LWIP_IPV6 && LWIP_ETHERNET */

View File

@@ -1,11 +1,5 @@
/**
* @file
*
* IPv6 version of ICMP, as per RFC 4443.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@@ -32,319 +26,154 @@
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Ivan Delamer <delamer@inicotech.com>
* Author: Adam Dunkels <adam@sics.se>
*
*
* 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_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/icmp6.h"
#include "lwip/prot/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/icmp.h"
#include "lwip/inet.h"
#include "lwip/ip.h"
#include "lwip/def.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
icmp6_input(struct pbuf *p, struct netif *inp)
icmp_input(struct pbuf *p, struct netif *inp)
{
struct icmp6_hdr *icmp6hdr;
struct pbuf *r;
const ip6_addr_t *reply_src;
u8_t type;
struct icmp_echo_hdr *iecho;
struct ip_hdr *iphdr;
struct ip_addr tmpaddr;
ICMP6_STATS_INC(icmp6.recv);
ICMP_STATS_INC(icmp.recv);
/* 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;
}
/* TODO: check length before accessing payload! */
icmp6hdr = (struct icmp6_hdr *)p->payload;
type = ((u8_t *)p->payload)[0];
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 CHECKSUM_CHECK_ICMP6
IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) {
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);
ICMP_STATS_INC(icmp.lenerr);
return;
}
}
#endif /* CHECKSUM_CHECK_ICMP6 */
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);
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;*/
}
#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;
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);
/* 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. */
#if LWIP_MULTICAST_PING
if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
reply_src = ip_2_ip6(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;
}
}
else
#endif /* LWIP_MULTICAST_PING */
{
reply_src = ip6_current_dest_addr();
}
/* Set fields in reply. */
((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP;
((struct icmp6_echo_hdr *)(r->payload))->chksum = 0;
#if CHECKSUM_GEN_ICMP6
IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) {
((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r,
IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr());
}
#endif /* CHECKSUM_GEN_ICMP6 */
/* 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:
ICMP6_STATS_INC(icmp6.proterr);
ICMP6_STATS_INC(icmp6.drop);
break;
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);
}
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
icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c)
{
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
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)
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
{
struct pbuf *q;
struct icmp6_hdr *icmp6hdr;
const ip6_addr_t *reply_src;
ip6_addr_t *reply_dest;
ip6_addr_t reply_src_local, reply_dest_local;
struct ip6_hdr *ip6hdr;
struct netif *netif;
struct ip_hdr *iphdr;
struct icmp_dur_hdr *idur;
/* ICMPv6 header + IPv6 header + data */
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE,
PBUF_RAM);
/* @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_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n"));
ICMP6_STATS_INC(icmp6.memerr);
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 6message",
(q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE)));
LWIP_ASSERT("check that first pbuf can hold icmp message",
(q->len >= (8 + IP_HLEN + 8)));
icmp6hdr = (struct icmp6_hdr *)q->payload;
icmp6hdr->type = type;
icmp6hdr->code = code;
icmp6hdr->data = data;
iphdr = p->payload;
/* copy fields from original packet */
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload,
IP6_HLEN + LWIP_ICMP6_DATASIZE);
idur = q->payload;
idur->type = (u8_t)ICMP6_DUR;
idur->icode = (u8_t)t;
/* Get the destination address and netif for this ICMP message. */
if ((ip_current_netif() == NULL) ||
((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) {
/* Special case, as ip6_current_xxx is either NULL, or points
* to a different packet than the one that expired.
* We must use the addresses that are stored in the expired packet. */
ip6hdr = (struct ip6_hdr *)p->payload;
/* copy from packed address to aligned address */
ip6_addr_copy(reply_dest_local, ip6hdr->src);
ip6_addr_copy(reply_src_local, ip6hdr->dest);
reply_dest = &reply_dest_local;
reply_src = &reply_src_local;
netif = ip6_route(reply_src, reply_dest);
if (netif == NULL) {
/* drop */
pbuf_free(q);
ICMP6_STATS_INC(icmp6.rterr);
return;
}
}
else {
netif = ip_current_netif();
reply_dest = ip6_current_src_addr();
/* Select an address to use as source. */
reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest));
if (reply_src == NULL) {
/* drop */
pbuf_free(q);
ICMP6_STATS_INC(icmp6.rterr);
return;
}
}
SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);
/* calculate checksum */
icmp6hdr->chksum = 0;
#if CHECKSUM_GEN_ICMP6
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len,
reply_src, reply_dest);
}
#endif /* CHECKSUM_GEN_ICMP6 */
idur->chksum = 0;
idur->chksum = inet_chksum(idur, q->len);
ICMP_STATS_INC(icmp.xmit);
ICMP6_STATS_INC(icmp6.xmit);
ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif);
ip_output(q, NULL,
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
pbuf_free(q);
}
#endif /* LWIP_ICMP6 && LWIP_IPV6 */
void
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
{
struct pbuf *q;
struct ip_hdr *iphdr;
struct icmp_te_hdr *tehdr;
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 */
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;
tehdr = q->payload;
tehdr->type = (u8_t)ICMP6_TE;
tehdr->icode = (u8_t)t;
/* copy fields from original packet */
SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);
/* 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);
pbuf_free(q);
}
#endif /* LWIP_ICMP */

View File

@@ -1,14 +1,15 @@
/**
* @file
* Functions common to all TCP/IPv6 modules, such as the Internet checksum and the
* byte order functions.
*
* INET v6 addresses.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* 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,
@@ -17,37 +18,146 @@
* 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>
*/
#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"
/** This variable is initialized by the system to contain the wildcard IPv6 address.
/* 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.
*/
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
#endif /* LWIP_IPV6 */
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);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,8 @@
/**
* @file
*
* IPv6 addresses.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* 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,
@@ -17,276 +11,62 @@
* 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>
*
* Functions for handling IPv6 addresses.
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#include "lwip/opt.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip_addr.h"
#include "lwip/def.h"
#include "lwip/inet.h"
/* used by IP6_ADDR_ANY(6) in ip6_addr.h */
const ip_addr_t ip6_addr_any = IPADDR6_INIT(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 representation (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)
u8_t
ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
struct ip_addr *mask)
{
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 (addr) {
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] == ':') {
if (s[2] == ':') {
/* invalid format: three successive colons */
return 0;
}
s++;
/* "::" found, set zeros */
while (zero_blocks > 0) {
zero_blocks--;
if (current_block_index & 0x1) {
addr_index++;
} else {
if (addr) {
addr->addr[addr_index] = 0;
}
}
current_block_index++;
if (current_block_index > 7) {
/* address too long! */
return 0;
}
}
}
} else if (isxdigit(*s)) {
/* add current digit */
current_block_value = (current_block_value << 4) +
(isdigit(*s) ? (u32_t)(*s - '0') :
(u32_t)(10 + (islower(*s) ? *s - 'a' : *s - 'A')));
} else {
/* unexpected digit, space? CRLF? */
break;
}
}
if (addr) {
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. */
if (addr) {
for (addr_index = 0; addr_index < 4; addr_index++) {
addr->addr[addr_index] = lwip_htonl(addr->addr[addr_index]);
}
}
if (current_block_index != 7) {
return 0;
}
return 1;
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]));
}
/**
* 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
* representation of addr
*/
char *
ip6addr_ntoa(const ip6_addr_t *addr)
u8_t
ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2)
{
static char str[40];
return ip6addr_ntoa_r(addr, str, 40);
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]);
}
/**
* 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)
void
ip_addr_set(struct ip_addr *dest, struct ip_addr *src)
{
u32_t current_block_index, current_block_value, next_block_value;
s32_t i;
u8_t zero_flag, empty_block_flag;
i = 0;
empty_block_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 = lwip_htonl(addr->addr[current_block_index >> 1]);
if ((current_block_index & 0x1) == 0) {
current_block_value = current_block_value >> 16;
}
current_block_value &= 0xffff;
/* Check for empty block. */
if (current_block_value == 0) {
if (current_block_index == 7 && empty_block_flag == 1) {
/* special case, we must render a ':' for the last block. */
buf[i++] = ':';
if (i >= buflen) {
return NULL;
}
break;
}
if (empty_block_flag == 0) {
/* generate empty block "::", but only if more than one contiguous zero block,
* according to current formatting suggestions RFC 5952. */
next_block_value = lwip_htonl(addr->addr[(current_block_index + 1) >> 1]);
if ((current_block_index & 0x1) == 0x01) {
next_block_value = next_block_value >> 16;
}
next_block_value &= 0xffff;
if (next_block_value == 0) {
empty_block_flag = 1;
buf[i++] = ':';
if (i >= buflen) {
return NULL;
}
continue; /* move on to next block. */
}
} else if (empty_block_flag == 1) {
/* move on to next block. */
continue;
}
} else if (empty_block_flag == 1) {
/* Set this flag value so we don't produce multiple empty blocks. */
empty_block_flag = 2;
}
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));
zero_flag = 0;
if (i >= buflen) {
return NULL;
}
}
if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
/* do nothing */
} else {
buf[i++] = xchar(((current_block_value & 0xf00) >> 8));
zero_flag = 0;
if (i >= buflen) {
return NULL;
}
}
if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
/* do nothing */
}
else {
buf[i++] = xchar(((current_block_value & 0xf0) >> 4));
zero_flag = 0;
if (i >= buflen) {
return NULL;
}
}
buf[i++] = xchar((current_block_value & 0xf));
if (i >= buflen) {
return NULL;
}
}
buf[i] = 0;
return buf;
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];*/
}
#endif /* LWIP_IPV6 */
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);
}

View File

@@ -1,805 +0,0 @@
/**
* @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/ip.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 */
#if IPV6_FRAG_COPYHEADER
#define IPV6_FRAG_REQROOM ((s16_t)(sizeof(struct ip6_reass_helper) - IP6_FRAG_HLEN))
#endif
#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;
#if !IPV6_FRAG_COPYHEADER
LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1",
sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN);
#endif /* !IPV6_FRAG_COPYHEADER */
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;
u16_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 ipv6 header (we are now pointing to Fragment header).
This cannot fail since we already checked when receiving this fragment. */
if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)IPV6_FRAG_HDRREF(ipr->iphdr)))) {
LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0);
}
else {
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 == ipr) {
/* nothing to free, ipr is the only element on the list */
return;
}
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
* @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;
u16_t clen;
u8_t valid = 1;
struct pbuf *q;
IP6_FRAG_STATS_INC(ip6_frag.recv);
if ((const void*)ip6_current_header() != ((u8_t*)p->payload) - IP6_HLEN) {
/* ip6_frag_hdr must be in the first pbuf, not chained */
IP6_FRAG_STATS_INC(ip6_frag.proterr);
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
}
frag_hdr = (struct ip6_frag_hdr *) p->payload;
clen = pbuf_clen(p);
offset = lwip_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 = lwip_ntohs(ip6_current_header()->_plen);
len -= (u16_t)(((u8_t*)p->payload - (const 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(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->src)) &&
ip6_addr_cmp(ip6_current_dest_addr(), &(IPV6_FRAG_HDRREF(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) {
/* re-search ipr_prev since it might have been removed */
for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) {
if (ipr_prev->next == ipr) {
break;
}
}
} else
#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). */
#if IPV6_FRAG_COPYHEADER
MEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN);
#else /* IPV6_FRAG_COPYHEADER */
/* need to use the none-const pointer here: */
ipr->iphdr = ip_data.current_ip6_header;
#endif /* IPV6_FRAG_COPYHEADER */
/* 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) {
/* re-search ipr_prev since it might have been removed */
for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) {
if (ipr_prev->next == ipr) {
break;
}
}
} else
#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. */
#if IPV6_FRAG_COPYHEADER
if (IPV6_FRAG_REQROOM > 0) {
/* Make room for struct ip6_reass_helper (only required if sizeof(void*) > 4).
This cannot fail since we already checked when receiving this fragment. */
u8_t hdrerr = pbuf_header_force(p, IPV6_FRAG_REQROOM);
LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
}
#else /* IPV6_FRAG_COPYHEADER */
LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1",
sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN);
#endif /* IPV6_FRAG_COPYHEADER */
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) {
#if IPV6_FRAG_COPYHEADER
if (iprh->next_pbuf != NULL) {
MEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN);
}
#else /* IPV6_FRAG_COPYHEADER */
/* need to use the none-const pointer here: */
ipr->iphdr = ip_data.current_ip6_header;
#endif /* IPV6_FRAG_COPYHEADER */
}
/* 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) && valid) {
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 */
struct ip6_hdr* iphdr_ptr;
/* chain together the pbufs contained within the ip6_reassdata list. */
iprh = (struct ip6_reass_helper*) ipr->p->payload;
while (iprh != NULL) {
struct pbuf* next_pbuf = iprh->next_pbuf;
if (next_pbuf != NULL) {
/* Save next helper struct (will be hidden in next step). */
iprh_tmp = (struct ip6_reass_helper*)next_pbuf->payload;
/* hide the fragment header for every succeeding fragment */
pbuf_header(next_pbuf, -IP6_FRAG_HLEN);
#if IPV6_FRAG_COPYHEADER
if (IPV6_FRAG_REQROOM > 0) {
/* hide the extra bytes borrowed from ip6_hdr for struct ip6_reass_helper */
u8_t hdrerr = pbuf_header(next_pbuf, -(s16_t)(IPV6_FRAG_REQROOM));
LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
}
#endif
pbuf_cat(ipr->p, next_pbuf);
}
else {
iprh_tmp = NULL;
}
iprh = iprh_tmp;
}
#if IPV6_FRAG_COPYHEADER
if (IPV6_FRAG_REQROOM > 0) {
/* get back room for struct ip6_reass_helper (only required if sizeof(void*) > 4) */
u8_t hdrerr = pbuf_header(ipr->p, -(s16_t)(IPV6_FRAG_REQROOM));
LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
}
iphdr_ptr = (struct ip6_hdr*)((u8_t*)ipr->p->payload - IP6_HLEN);
MEMCPY(iphdr_ptr, &ipr->iphdr, IP6_HLEN);
#else
iphdr_ptr = ipr->iphdr;
#endif
/* Adjust datagram length by adding header lengths. */
ipr->datagram_len += (u16_t)(((u8_t*)ipr->p->payload - (u8_t*)iphdr_ptr)
+ IP6_FRAG_HLEN
- IP6_HLEN);
/* Set payload length in ip header. */
iphdr_ptr->_plen = lwip_htons(ipr->datagram_len);
/* Get the first 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;
/* 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);
/* adjust the number of pbufs currently queued for reassembly. */
ip6_reass_pbufcount -= pbuf_clen(p);
/* Move pbuf back to IPv6 header.
This cannot fail since we already checked when receiving this fragment. */
if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)iphdr_ptr))) {
LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0);
pbuf_free(p);
return NULL;
}
/* 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
#if !LWIP_NETIF_TX_SINGLE_PBUF
/** 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);
}
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
/**
* 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, const ip6_addr_t *dest)
{
struct ip6_hdr *original_ip6hdr;
struct ip6_hdr *ip6hdr;
struct ip6_frag_hdr *frag_hdr;
struct pbuf *rambuf;
#if !LWIP_NETIF_TX_SINGLE_PBUF
struct pbuf *newpbuf;
u16_t newpbuflen = 0;
u16_t left_to_copy;
#endif
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;
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;
#if LWIP_NETIF_TX_SINGLE_PBUF
rambuf = pbuf_alloc(PBUF_IP, cop + 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!",
(rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
poff += pbuf_copy_partial(p, (u8_t*)rambuf->payload + IP6_FRAG_HLEN, cop, poff);
/* make room for the IP header */
if (pbuf_header(rambuf, IP6_HLEN)) {
pbuf_free(rambuf);
IP6_FRAG_STATS_INC(ip6_frag.memerr);
return ERR_MEM;
}
/* fill in the IP header */
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);
#else
/* 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)));
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;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
/* Set headers */
frag_hdr->_nexth = original_ip6hdr->_nexth;
frag_hdr->reserved = 0;
frag_hdr->_fragment_offset = lwip_htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG));
frag_hdr->_identification = lwip_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 */

View File

@@ -1,588 +0,0 @@
/**
* @file
* Multicast listener discovery
*
* @defgroup mld6 MLD6
* @ingroup ip6
* Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710.
* No support for MLDv2.\n
* To be called from TCPIP thread
*/
/*
* 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 && LWIP_IPV6_MLD /* don't build if not configured for use in lwipopts.h */
#include "lwip/mld6.h"
#include "lwip/prot/mld6.h"
#include "lwip/icmp6.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/ip.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
/* Forward declarations. */
static struct mld_group *mld6_new_group(struct netif *ifp, const ip6_addr_t *addr);
static err_t mld6_remove_group(struct netif *netif, struct mld_group *group);
static void mld6_delayed_report(struct mld_group *group, u16_t maxresp);
static void mld6_send(struct netif *netif, 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 = netif_mld6_data(netif);
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, NULL);
while (group != NULL) {
struct mld_group *next = group->next; /* avoid use-after-free below */
/* disable the group at the MAC level */
if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER);
}
/* free group */
memp_free(MEMP_MLD6_GROUP, 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 = netif_mld6_data(netif);
while (group != NULL) {
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, const ip6_addr_t *addr)
{
struct mld_group *group = netif_mld6_data(ifp);
while (group != NULL) {
if (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, const ip6_addr_t *addr)
{
struct mld_group *group;
group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP);
if (group != NULL) {
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 = netif_mld6_data(ifp);
netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group);
}
return group;
}
/**
* Remove a group from the mld_group_list, but do not free it yet
*
* @param group the group to remove
* @return ERR_OK if group was removed from the list, an err_t otherwise
*/
static err_t
mld6_remove_group(struct netif *netif, struct mld_group *group)
{
err_t err = ERR_OK;
/* Is it the first group? */
if (netif_mld6_data(netif) == group) {
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group->next);
} else {
/* look for group further down the list */
struct mld_group *tmpGroup;
for (tmpGroup = netif_mld6_data(netif); tmpGroup != NULL; tmpGroup = tmpGroup->next) {
if (tmpGroup->next == group) {
tmpGroup->next = group->next;
break;
}
}
/* Group not find group */
if (tmpGroup == NULL) {
err = ERR_ARG;
}
}
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 = netif_mld6_data(inp);
while (group != NULL) {
if ((!(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);
}
/**
* @ingroup mld6
* 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(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr)
{
err_t err = ERR_VAL; /* no matching interface */
struct netif *netif;
/* loop through netif's */
netif = netif_list;
while (netif != NULL) {
/* Should we join this interface ? */
if (ip6_addr_isany(srcaddr) ||
netif_get_ip6_addr_match(netif, srcaddr) >= 0) {
err = mld6_joingroup_netif(netif, groupaddr);
if (err != ERR_OK) {
return err;
}
}
/* proceed to next network interface */
netif = netif->next;
}
return err;
}
/**
* @ingroup mld6
* Join a group on a network interface.
*
* @param netif the network interface which should join a new group.
* @param groupaddr the ipv6 address of the group to join
* @return ERR_OK if group was joined on the netif, an err_t otherwise
*/
err_t
mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
{
struct mld_group *group;
/* 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, NETIF_ADD_MAC_FILTER);
}
/* Report our membership. */
MLD6_STATS_INC(mld6.tx_report);
mld6_send(netif, group, ICMP6_TYPE_MLR);
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
}
/* Increment group use */
group->use++;
return ERR_OK;
}
/**
* @ingroup mld6
* 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(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr)
{
err_t err = ERR_VAL; /* no matching interface */
struct netif *netif;
/* loop through netif's */
netif = netif_list;
while (netif != NULL) {
/* Should we leave this interface ? */
if (ip6_addr_isany(srcaddr) ||
netif_get_ip6_addr_match(netif, srcaddr) >= 0) {
err_t res = mld6_leavegroup_netif(netif, groupaddr);
if (err != ERR_OK) {
/* Store this result if we have not yet gotten a success */
err = res;
}
}
/* proceed to next network interface */
netif = netif->next;
}
return err;
}
/**
* @ingroup mld6
* Leave a group on a network interface.
*
* @param netif the network interface which should leave the group.
* @param groupaddr the ipv6 address of the group to leave
* @return ERR_OK if group was left on the netif, an err_t otherwise
*/
err_t
mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
{
struct mld_group *group;
/* 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) {
/* Remove the group from the list */
mld6_remove_group(netif, group);
/* If we are the last reporter for this group */
if (group->last_reporter_flag) {
MLD6_STATS_INC(mld6.tx_leave);
mld6_send(netif, group, ICMP6_TYPE_MLD);
}
/* Disable the group at the MAC level */
if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER);
}
/* free group struct */
memp_free(MEMP_MLD6_GROUP, group);
} else {
/* Decrement group use */
group->use--;
}
/* Left group */
return ERR_OK;
}
/* Group not found */
return ERR_VAL;
}
/**
* 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 netif *netif = netif_list;
while (netif != NULL) {
struct mld_group *group = netif_mld6_data(netif);
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(netif, group, ICMP6_TYPE_MLR);
group->group_state = MLD6_GROUP_IDLE_MEMBER;
}
}
}
group = group->next;
}
netif = netif->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;
}
#ifdef LWIP_RAND
/* Randomize maxresp. (if LWIP_RAND is supported) */
maxresp = LWIP_RAND() % maxresp;
if (maxresp == 0) {
maxresp = 1;
}
#endif /* LWIP_RAND */
/* 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 netif *netif, struct mld_group *group, u8_t type)
{
struct mld_header *mld_hdr;
struct pbuf *p;
const 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) {
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(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_ANY6;
} else {
/* Use link-local address as source address. */
src_addr = netif_ip6_addr(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));
#if CHECKSUM_GEN_ICMP6
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len,
src_addr, &(group->group_address));
}
#endif /* CHECKSUM_GEN_ICMP6 */
/* 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);
if (type == ICMP6_TYPE_MLR) {
/* Remember we were the last to report */
group->last_reporter_flag = 1;
}
/* 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, netif);
pbuf_free(p);
}
#endif /* LWIP_IPV6 */

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@
*
* To let mem_malloc() use pools (prevents fragmentation and is much faster than
* a heap but might waste some memory), define MEM_USE_POOLS to 1, define
* MEMP_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
* MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
* of pools like this (more pools can be added between _START and _END):
*
* Define three pools with sizes 256, 512, and 1512 bytes
@@ -54,106 +54,19 @@
*/
#include "lwip/opt.h"
#include "lwip/mem.h"
#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
#include "lwip/err.h"
#include <string.h>
#if MEM_LIBC_MALLOC
#include <stdlib.h> /* for malloc()/free() */
#endif
#if MEM_LIBC_MALLOC || MEM_USE_POOLS
/** mem_init is not used when using pools instead of a heap or using
* C library malloc().
*/
void
mem_init(void)
{
}
/** mem_trim is not used when using pools instead of a heap or using
* C library malloc(): we can't free part of a pool element and the stack
* support mem_trim() to return a different pointer
*/
void*
mem_trim(void *mem, mem_size_t size)
{
LWIP_UNUSED_ARG(size);
return mem;
}
#endif /* MEM_LIBC_MALLOC || MEM_USE_POOLS */
#if MEM_LIBC_MALLOC
/* lwIP heap implemented using C library malloc() */
/* in case C library malloc() needs extra protection,
* allow these defines to be overridden.
*/
#ifndef mem_clib_free
#define mem_clib_free free
#endif
#ifndef mem_clib_malloc
#define mem_clib_malloc malloc
#endif
#ifndef mem_clib_calloc
#define mem_clib_calloc calloc
#endif
#if LWIP_STATS && MEM_STATS
#define MEM_LIBC_STATSHELPER_SIZE LWIP_MEM_ALIGN_SIZE(sizeof(mem_size_t))
#else
#define MEM_LIBC_STATSHELPER_SIZE 0
#endif
/**
* Allocate a block of memory with a minimum of 'size' bytes.
*
* @param size is the minimum size of the requested block in bytes.
* @return pointer to allocated memory or NULL if no free memory was found.
*
* Note that the returned value must always be aligned (as defined by MEM_ALIGNMENT).
*/
void *
mem_malloc(mem_size_t size)
{
void* ret = mem_clib_malloc(size + MEM_LIBC_STATSHELPER_SIZE);
if (ret == NULL) {
MEM_STATS_INC(err);
} else {
LWIP_ASSERT("malloc() must return aligned memory", LWIP_MEM_ALIGN(ret) == ret);
#if LWIP_STATS && MEM_STATS
*(mem_size_t*)ret = size;
ret = (u8_t*)ret + MEM_LIBC_STATSHELPER_SIZE;
MEM_STATS_INC_USED(used, size);
#endif
}
return ret;
}
/** Put memory back on the heap
*
* @param rmem is the pointer as returned by a previous call to mem_malloc()
*/
void
mem_free(void *rmem)
{
LWIP_ASSERT("rmem != NULL", (rmem != NULL));
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
#if LWIP_STATS && MEM_STATS
rmem = (u8_t*)rmem - MEM_LIBC_STATSHELPER_SIZE;
MEM_STATS_DEC_USED(used, *(mem_size_t*)rmem);
#endif
mem_clib_free(rmem);
}
#elif MEM_USE_POOLS
/* lwIP heap implemented with different sized pools */
#if MEM_USE_POOLS
/* lwIP head implemented with different sized pools */
/**
* Allocate memory: determine the smallest pool that is big enough
@@ -166,32 +79,35 @@ void *
mem_malloc(mem_size_t size)
{
void *ret;
struct memp_malloc_helper *element = NULL;
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 = (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 memp_malloc_helper that saves the pool this element came from? */
if (required_size <= memp_pools[poolnr]->size) {
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 */
#if MEM_USE_POOLS_TRY_BIGGER_POOL
/** Try a bigger pool if this one is empty! */
if (poolnr < MEMP_POOL_LAST) {
continue;
}
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
MEM_STATS_INC(err);
return NULL;
}
if (required_size <= memp_sizes[poolnr]) {
break;
}
}
if (poolnr > MEMP_POOL_LAST) {
LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
MEM_STATS_INC(err);
return NULL;
}
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 */
#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;
}
@@ -200,15 +116,6 @@ mem_malloc(mem_size_t size)
/* 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));
#if MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS)
/* truncating to u16_t is safe because struct memp_desc::size is u16_t */
element->size = (u16_t)size;
MEM_STATS_INC_USED(used, element->size);
#endif /* MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) */
#if MEMP_OVERFLOW_CHECK
/* initialize unused memory (diff between requested size and selected pool's size) */
memset((u8_t*)ret + size, 0xcd, memp_pools[poolnr]->size - size);
#endif /* MEMP_OVERFLOW_CHECK */
return ret;
}
@@ -228,27 +135,12 @@ mem_free(void *rmem)
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
/* get the original struct memp_malloc_helper */
/* cast through void* to get rid of alignment warnings */
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)));
LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));
MEM_STATS_DEC_USED(used, hmem->size);
#if MEMP_OVERFLOW_CHECK
{
u16_t i;
LWIP_ASSERT("MEM_USE_POOLS: invalid chunk size",
hmem->size <= memp_pools[hmem->poolnr]->size);
/* check that unused memory remained untouched (diff between requested size and selected pool's size) */
for (i = hmem->size; i < memp_pools[hmem->poolnr]->size; i++) {
u8_t data = *((u8_t*)rmem + i);
LWIP_ASSERT("MEM_USE_POOLS: mem overflow detected", data == 0xcd);
}
}
#endif /* MEMP_OVERFLOW_CHECK */
/* and put it in the pool we saved earlier */
memp_free(hmem->poolnr, hmem);
}
@@ -259,7 +151,7 @@ mem_free(void *rmem)
/**
* The heap is made up as a list of structs of this type.
* This does not have to be aligned since for getting its size,
* we only use the macro SIZEOF_STRUCT_MEM, which automatically aligns.
* we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.
*/
struct mem {
/** index (-> ram[next]) of the next struct */
@@ -287,7 +179,7 @@ struct mem {
* 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 */
LWIP_DECLARE_MEMORY_ALIGNED(ram_heap, MEM_SIZE_ALIGNED + (2U*SIZEOF_STRUCT_MEM));
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 */
@@ -404,7 +296,7 @@ mem_init(void)
MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
if (sys_mutex_new(&mem_mutex) != ERR_OK) {
if(sys_mutex_new(&mem_mutex) != ERR_OK) {
LWIP_ASSERT("failed to create mem_mutex", 0);
}
}
@@ -442,7 +334,6 @@ mem_free(void *rmem)
/* protect the heap from concurrent access */
LWIP_MEM_FREE_PROTECT();
/* Get the corresponding struct mem ... */
/* cast through void* to get rid of alignment warnings */
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);
@@ -487,7 +378,7 @@ mem_trim(void *rmem, mem_size_t newsize)
adjust for alignment. */
newsize = LWIP_MEM_ALIGN_SIZE(newsize);
if (newsize < MIN_SIZE_ALIGNED) {
if(newsize < MIN_SIZE_ALIGNED) {
/* every data block must be at least MIN_SIZE_ALIGNED long */
newsize = MIN_SIZE_ALIGNED;
}
@@ -509,7 +400,6 @@ mem_trim(void *rmem, mem_size_t newsize)
return rmem;
}
/* Get the corresponding struct mem ... */
/* cast through void* to get rid of alignment warnings */
mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
/* ... and its offset pointer */
ptr = (mem_size_t)((u8_t *)mem - ram);
@@ -529,7 +419,7 @@ mem_trim(void *rmem, mem_size_t newsize)
LWIP_MEM_FREE_PROTECT();
mem2 = (struct mem *)(void *)&ram[mem->next];
if (mem2->used == 0) {
if(mem2->used == 0) {
/* The next struct is unused, we can simply move it at little */
mem_size_t next;
/* remember the old next pointer */
@@ -581,7 +471,7 @@ mem_trim(void *rmem, mem_size_t newsize)
/* else {
next struct mem is used but size between mem and mem2 is not big enough
to create another struct mem
-> don't do anyhting.
-> don't do anyhting.
-> the remaining space stays unused since it is too small
} */
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
@@ -592,6 +482,7 @@ mem_trim(void *rmem, mem_size_t newsize)
}
/**
* Adam's mem_malloc() plus solution for bug #17922
* Allocate a block of memory with a minimum of 'size' bytes.
*
* @param size is the minimum size of the requested block in bytes.
@@ -617,7 +508,7 @@ mem_malloc(mem_size_t size)
adjust for alignment. */
size = LWIP_MEM_ALIGN_SIZE(size);
if (size < MIN_SIZE_ALIGNED) {
if(size < MIN_SIZE_ALIGNED) {
/* every data block must be at least MIN_SIZE_ALIGNED long */
size = MIN_SIZE_ALIGNED;
}
@@ -688,7 +579,7 @@ mem_malloc(mem_size_t size)
/* (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 exact fit: do not split, no mem2 creation
* -> 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!
*/
@@ -732,7 +623,7 @@ mem_malloc_adjust_lfree:
}
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
/* if we got interrupted by a mem_free, try again */
} while (local_mem_free_count != 0);
} 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);
@@ -742,15 +633,6 @@ mem_malloc_adjust_lfree:
}
#endif /* MEM_USE_POOLS */
#if MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS)
void *
mem_calloc(mem_size_t count, mem_size_t size)
{
return mem_clib_calloc(count, size);
}
#else /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */
/**
* Contiguously allocates enough space for count objects that are size bytes
* of memory each and returns a pointer to the allocated memory.
@@ -761,8 +643,7 @@ mem_calloc(mem_size_t count, mem_size_t size)
* @param size size of the objects to allocate
* @return pointer to allocated memory / NULL pointer if there is an error
*/
void *
mem_calloc(mem_size_t count, mem_size_t size)
void *mem_calloc(mem_size_t count, mem_size_t size)
{
void *p;
@@ -770,8 +651,9 @@ mem_calloc(mem_size_t count, mem_size_t size)
p = mem_malloc(count * size);
if (p) {
/* zero the memory */
memset(p, 0, (size_t)count * (size_t)size);
memset(p, 0, count * size);
}
return p;
}
#endif /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */
#endif /* !MEM_LIBC_MALLOC */

View File

@@ -4,18 +4,13 @@
*
* lwIP has dedicated pools for many structures (netconn, protocol control blocks,
* packet buffers, ...). All these pools are managed here.
*
* @defgroup mempool Memory pools
* @ingroup infrastructure
* Custom memory pools
*/
/*
* 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,
@@ -24,21 +19,21 @@
* 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>
*
*/
@@ -46,102 +41,201 @@
#include "lwip/opt.h"
#include "lwip/memp.h"
#include "lwip/pbuf.h"
#include "lwip/udp.h"
#include "lwip/raw.h"
#include "lwip/tcp_impl.h"
#include "lwip/igmp.h"
#include "lwip/api.h"
#include "lwip/api_msg.h"
#include "lwip/tcpip.h"
#include "lwip/sys.h"
#include "lwip/timers.h"
#include "lwip/stats.h"
#include "netif/etharp.h"
#include "lwip/ip_frag.h"
#include "lwip/snmp_structs.h"
#include "lwip/snmp_msg.h"
#include "lwip/dns.h"
#include "netif/ppp_oe.h"
#include <string.h>
/* Make sure we include everything we need for size calculation required by memp_std.h */
#include "lwip/pbuf.h"
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/ip4_frag.h"
#include "lwip/netbuf.h"
#include "lwip/api.h"
#include "lwip/priv/tcpip_priv.h"
#include "lwip/priv/api_msg.h"
#include "lwip/sockets.h"
#include "lwip/netifapi.h"
#include "lwip/etharp.h"
#include "lwip/igmp.h"
#include "lwip/timeouts.h"
/* needed by default MEMP_NUM_SYS_TIMEOUT */
#include "netif/ppp/ppp_opts.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "lwip/priv/nd6_priv.h"
#include "lwip/ip6_frag.h"
#include "lwip/mld6.h"
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc)
#include "lwip/priv/memp_std.h"
const struct memp_desc* const memp_pools[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name,
#include "lwip/priv/memp_std.h"
struct memp {
struct memp *next;
#if MEMP_OVERFLOW_CHECK
const char *file;
int line;
#endif /* MEMP_OVERFLOW_CHECK */
};
#ifdef LWIP_HOOK_FILENAME
#include LWIP_HOOK_FILENAME
#endif
#if MEMP_OVERFLOW_CHECK
/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
* and at the end of each element, initialize them as 0xcd and check
* them later. */
/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
* every single element in each pool is checked!
* This is VERY SLOW but also very helpful. */
/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
* lwipopts.h to change the amount reserved for checking. */
#ifndef MEMP_SANITY_REGION_BEFORE
#define MEMP_SANITY_REGION_BEFORE 16
#endif /* MEMP_SANITY_REGION_BEFORE*/
#if MEMP_SANITY_REGION_BEFORE > 0
#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
#else
#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0
#endif /* MEMP_SANITY_REGION_BEFORE*/
#ifndef MEMP_SANITY_REGION_AFTER
#define MEMP_SANITY_REGION_AFTER 16
#endif /* MEMP_SANITY_REGION_AFTER*/
#if MEMP_SANITY_REGION_AFTER > 0
#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
#else
#define MEMP_SANITY_REGION_AFTER_ALIGNED 0
#endif /* MEMP_SANITY_REGION_AFTER*/
#if MEMP_MEM_MALLOC && MEMP_OVERFLOW_CHECK >= 2
#undef MEMP_OVERFLOW_CHECK
/* MEMP_OVERFLOW_CHECK >= 2 does not work with MEMP_MEM_MALLOC, use 1 instead */
#define MEMP_OVERFLOW_CHECK 1
#endif
/* MEMP_SIZE: save space for struct memp and for sanity check */
#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
#if MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC
#else /* MEMP_OVERFLOW_CHECK */
/* No sanity checks
* We don't need to preserve the struct memp while not allocated, so we
* can save a little space and set MEMP_SIZE to 0.
*/
#define MEMP_SIZE 0
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
#endif /* MEMP_OVERFLOW_CHECK */
/** This array holds the first free element of each pool.
* 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 && !MEMP_MEM_MALLOC
static
#endif
const u16_t memp_sizes[MEMP_MAX] = {
#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),
#include "lwip/memp_std.h"
};
/** This array holds a textual description of each pool. */
#ifdef LWIP_DEBUG
static const char *memp_desc[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) (desc),
#include "lwip/memp_std.h"
};
#endif /* LWIP_DEBUG */
#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, using "Floyd's cycle-finding algorithm".
* Check that memp-lists don't form a circle
*/
static int
memp_sanity(const struct memp_desc *desc)
memp_sanity(void)
{
struct memp *t, *h;
s16_t i, c;
struct memp *m, *n;
t = *desc->tab;
if (t != NULL) {
for (h = t->next; (t != NULL) && (h != NULL); t = t->next,
h = ((h->next != NULL) ? h->next->next : NULL)) {
if (t == h) {
return 0;
for (i = 0; i < MEMP_MAX; i++) {
for (m = memp_tab[i]; m != NULL; m = m->next) {
c = 1;
for (n = memp_tab[i]; n != NULL; n = n->next) {
if (n == m && --c < 0) {
return 0;
}
}
}
}
return 1;
}
#endif /* MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC */
#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 desc the pool p comes from
* @param memp_type the pool p comes from
*/
static void
memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *desc)
memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)
{
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
u16_t k;
u8_t *m;
m = (u8_t*)p + MEMP_SIZE + desc->size;
#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 ";
strcat(errstr, desc->desc);
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);
}
}
#else /* MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
LWIP_UNUSED_ARG(p);
LWIP_UNUSED_ARG(desc);
#endif /* MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
#endif
}
/**
@@ -149,51 +243,34 @@ memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *des
* (e.g. the restricted area before it has been altered)
*
* @param p the memp element to check
* @param desc the pool p comes from
* @param memp_type the pool p comes from
*/
static void
memp_overflow_check_element_underflow(struct memp *p, const struct memp_desc *desc)
memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type)
{
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
u16_t k;
u8_t *m;
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
if (m[k] != 0xcd) {
char errstr[128] = "detected memp underflow in pool ";
strcat(errstr, desc->desc);
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);
}
}
#else /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 */
LWIP_UNUSED_ARG(p);
LWIP_UNUSED_ARG(desc);
#endif /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 */
#endif
}
/**
* Initialize the restricted area of on memp element.
*/
static void
memp_overflow_init_element(struct memp *p, const struct memp_desc *desc)
{
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0
u8_t *m;
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
#endif
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE + desc->size;
memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
#endif
#else /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
LWIP_UNUSED_ARG(p);
LWIP_UNUSED_ARG(desc);
#endif /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
}
#if MEMP_OVERFLOW_CHECK >= 2
/**
* Do an overflow check for all elements in every pool.
*
@@ -204,173 +281,96 @@ memp_overflow_check_all(void)
{
u16_t i, j;
struct memp *p;
SYS_ARCH_DECL_PROTECT(old_level);
SYS_ARCH_PROTECT(old_level);
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
for (i = 0; i < MEMP_MAX; ++i) {
p = (struct memp*)LWIP_MEM_ALIGN(memp_pools[i]->base);
for (j = 0; j < memp_pools[i]->num; ++j) {
memp_overflow_check_element_overflow(p, memp_pools[i]);
memp_overflow_check_element_underflow(p, memp_pools[i]);
p = LWIP_ALIGNMENT_CAST(struct memp*, ((u8_t*)p + MEMP_SIZE + memp_pools[i]->size + MEMP_SANITY_REGION_AFTER_ALIGNED));
p = p;
for (j = 0; j < memp_num[i]; ++j) {
memp_overflow_check_element_overflow(p, i);
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
}
}
SYS_ARCH_UNPROTECT(old_level);
}
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
#endif /* MEMP_OVERFLOW_CHECK */
/**
* Initialize custom memory pool.
* Related functions: memp_malloc_pool, memp_free_pool
*
* @param desc pool to initialize
*/
void
memp_init_pool(const struct memp_desc *desc)
{
#if MEMP_MEM_MALLOC
LWIP_UNUSED_ARG(desc);
#else
int i;
struct memp *memp;
*desc->tab = NULL;
memp = (struct memp*)LWIP_MEM_ALIGN(desc->base);
/* create a linked list of memp elements */
for (i = 0; i < desc->num; ++i) {
memp->next = *desc->tab;
*desc->tab = memp;
#if MEMP_OVERFLOW_CHECK
memp_overflow_init_element(memp, desc);
#endif /* MEMP_OVERFLOW_CHECK */
/* cast through void* to get rid of alignment warnings */
memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size
#if MEMP_OVERFLOW_CHECK
+ MEMP_SANITY_REGION_AFTER_ALIGNED
#endif
);
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);
}
}
#if MEMP_STATS
desc->stats->avail = desc->num;
#endif /* MEMP_STATS */
#endif /* !MEMP_MEM_MALLOC */
#if MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY)
desc->stats->name = desc->desc;
#endif /* MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) */
}
/**
* Initializes lwIP built-in pools.
* Related functions: memp_malloc, memp_free
*
* Initialize the restricted areas of all memp elements in every pool.
*/
static void
memp_overflow_init(void)
{
u16_t i, j;
struct memp *p;
u8_t *m;
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) {
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
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];
memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
#endif
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
}
}
}
#endif /* MEMP_OVERFLOW_CHECK */
/**
* Initialize this module.
*
* Carves out memp_memory into linked lists for each pool-type.
*/
void
memp_init(void)
{
u16_t i;
struct memp *memp;
u16_t i, j;
/* for every pool: */
for (i = 0; i < LWIP_ARRAYSIZE(memp_pools); i++) {
memp_init_pool(memp_pools[i]);
#if LWIP_STATS && MEMP_STATS
lwip_stats.memp[i] = memp_pools[i]->stats;
#endif
for (i = 0; i < MEMP_MAX; ++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]);
}
#if MEMP_OVERFLOW_CHECK >= 2
#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 *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
#if MEMP_OVERFLOW_CHECK
+ MEMP_SANITY_REGION_AFTER_ALIGNED
#endif
);
}
}
#if MEMP_OVERFLOW_CHECK
memp_overflow_init();
/* check everything a first time to see if it worked */
memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
}
static void*
#if !MEMP_OVERFLOW_CHECK
do_memp_malloc_pool(const struct memp_desc *desc)
#else
do_memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int line)
#endif
{
struct memp *memp;
SYS_ARCH_DECL_PROTECT(old_level);
#if MEMP_MEM_MALLOC
memp = (struct memp *)mem_malloc(MEMP_SIZE + MEMP_ALIGN_SIZE(desc->size));
SYS_ARCH_PROTECT(old_level);
#else /* MEMP_MEM_MALLOC */
SYS_ARCH_PROTECT(old_level);
memp = *desc->tab;
#endif /* MEMP_MEM_MALLOC */
if (memp != NULL) {
#if !MEMP_MEM_MALLOC
#if MEMP_OVERFLOW_CHECK == 1
memp_overflow_check_element_overflow(memp, desc);
memp_overflow_check_element_underflow(memp, desc);
#endif /* MEMP_OVERFLOW_CHECK */
*desc->tab = memp->next;
#if MEMP_OVERFLOW_CHECK
memp->next = NULL;
#endif /* MEMP_OVERFLOW_CHECK */
#endif /* !MEMP_MEM_MALLOC */
#if MEMP_OVERFLOW_CHECK
memp->file = file;
memp->line = line;
#if MEMP_MEM_MALLOC
memp_overflow_init_element(memp, desc);
#endif /* MEMP_MEM_MALLOC */
#endif /* MEMP_OVERFLOW_CHECK */
LWIP_ASSERT("memp_malloc: memp properly aligned",
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
#if MEMP_STATS
desc->stats->used++;
if (desc->stats->used > desc->stats->max) {
desc->stats->max = desc->stats->used;
}
#endif
SYS_ARCH_UNPROTECT(old_level);
/* cast through u8_t* to get rid of alignment warnings */
return ((u8_t*)memp + MEMP_SIZE);
} else {
LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", desc->desc));
#if MEMP_STATS
desc->stats->err++;
#endif
}
SYS_ARCH_UNPROTECT(old_level);
return NULL;
}
/**
* Get an element from a custom pool.
*
* @param desc the pool to get an element from
*
* @return a pointer to the allocated memory or a NULL pointer on error
*/
void *
#if !MEMP_OVERFLOW_CHECK
memp_malloc_pool(const struct memp_desc *desc)
#else
memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int line)
#endif
{
LWIP_ASSERT("invalid pool desc", desc != NULL);
if (desc == NULL) {
return NULL;
}
#if !MEMP_OVERFLOW_CHECK
return do_memp_malloc_pool(desc);
#else
return do_memp_malloc_pool_fn(desc, file, line);
#endif
}
/**
@@ -378,6 +378,10 @@ memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int li
*
* @param type the pool to get an element from
*
* the debug version has two more parameters:
* @param file file name calling this function
* @param line number of line where this function is called
*
* @return a pointer to the allocated memory or a NULL pointer on error
*/
void *
@@ -387,76 +391,37 @@ memp_malloc(memp_t type)
memp_malloc_fn(memp_t type, const char* file, const int line)
#endif
{
void *memp;
struct memp *memp;
SYS_ARCH_DECL_PROTECT(old_level);
LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);
SYS_ARCH_PROTECT(old_level);
#if MEMP_OVERFLOW_CHECK >= 2
memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
#if !MEMP_OVERFLOW_CHECK
memp = do_memp_malloc_pool(memp_pools[type]);
#else
memp = do_memp_malloc_pool_fn(memp_pools[type], file, line);
#endif
return memp;
}
static void
do_memp_free_pool(const struct memp_desc* desc, void *mem)
{
struct memp *memp;
SYS_ARCH_DECL_PROTECT(old_level);
LWIP_ASSERT("memp_free: mem properly aligned",
((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
/* cast through void* to get rid of alignment warnings */
memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);
SYS_ARCH_PROTECT(old_level);
#if MEMP_OVERFLOW_CHECK == 1
memp_overflow_check_element_overflow(memp, desc);
memp_overflow_check_element_underflow(memp, desc);
memp = memp_tab[type];
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
desc->stats->used--;
#endif
#if MEMP_MEM_MALLOC
LWIP_UNUSED_ARG(desc);
SYS_ARCH_UNPROTECT(old_level);
mem_free(memp);
#else /* MEMP_MEM_MALLOC */
memp->next = *desc->tab;
*desc->tab = memp;
#if MEMP_SANITY_CHECK
LWIP_ASSERT("memp sanity", memp_sanity(desc));
#endif /* MEMP_SANITY_CHECK */
SYS_ARCH_UNPROTECT(old_level);
#endif /* !MEMP_MEM_MALLOC */
}
/**
* Put a custom pool element back into its pool.
*
* @param desc the pool where to put mem
* @param mem the memp element to free
*/
void
memp_free_pool(const struct memp_desc* desc, void *mem)
{
LWIP_ASSERT("invalid pool desc", desc != NULL);
if ((desc == NULL) || (mem == NULL)) {
return;
MEMP_STATS_INC_USED(used, type);
LWIP_ASSERT("memp_malloc: memp properly aligned",
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);
} else {
LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
MEMP_STATS_INC(err, type);
}
do_memp_free_pool(desc, mem);
SYS_ARCH_UNPROTECT(old_level);
return memp;
}
/**
@@ -468,29 +433,37 @@ memp_free_pool(const struct memp_desc* desc, void *mem)
void
memp_free(memp_t type, void *mem)
{
#ifdef LWIP_HOOK_MEMP_AVAILABLE
struct memp *old_first;
#endif
LWIP_ERROR("memp_free: type < MEMP_MAX", (type < MEMP_MAX), return;);
struct memp *memp;
SYS_ARCH_DECL_PROTECT(old_level);
if (mem == NULL) {
return;
}
LWIP_ASSERT("memp_free: mem properly aligned",
((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
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_overflow(memp, type);
memp_overflow_check_element_underflow(memp, type);
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
#endif /* MEMP_OVERFLOW_CHECK */
#ifdef LWIP_HOOK_MEMP_AVAILABLE
old_first = *memp_pools[type]->tab;
#endif
MEMP_STATS_DEC(used, type);
memp->next = memp_tab[type];
memp_tab[type] = memp;
do_memp_free_pool(memp_pools[type], mem);
#if MEMP_SANITY_CHECK
LWIP_ASSERT("memp sanity", memp_sanity());
#endif /* MEMP_SANITY_CHECK */
#ifdef LWIP_HOOK_MEMP_AVAILABLE
if (old_first == NULL) {
LWIP_HOOK_MEMP_AVAILABLE(type);
}
#endif
SYS_ARCH_UNPROTECT(old_level);
}
#endif /* MEMP_MEM_MALLOC */

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,6 @@
/**
* @file
* Packet buffer management
*/
/**
* @defgroup pbuf Packet buffers (PBUF)
* @ingroup infrastructure
*
* Packets are built from the pbuf data structure. It supports dynamic
* memory allocation for packet contents or can reference externally
@@ -17,13 +12,13 @@
*
* Multiple packets may be queued, also using this singly linked list.
* This is called a "packet queue".
*
*
* So, a packet queue consists of one or more pbuf chains, each of
* which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE
* NOT SUPPORTED!!! Use helper structs to queue multiple packets.
*
*
* The differences between a pbuf chain and a packet queue are very
* precise but subtle.
* precise but subtle.
*
* The last pbuf of a packet has a ->tot_len field that equals the
* ->len field. It can be found by traversing the list. If the last
@@ -32,49 +27,6 @@
*
* Therefore, looping through a pbuf of a single packet, has an
* loop end condition (tot_len == p->len), NOT (next == NULL).
*
* Example of custom pbuf usage for zero-copy RX:
@code{.c}
typedef struct my_custom_pbuf
{
struct pbuf_custom p;
void* dma_descriptor;
} my_custom_pbuf_t;
LWIP_MEMPOOL_DECLARE(RX_POOL, 10, sizeof(my_custom_pbuf_t), "Zero-copy RX PBUF pool");
void my_pbuf_free_custom(void* p)
{
my_custom_pbuf_t* my_puf = (my_custom_pbuf_t*)p;
LOCK_INTERRUPTS();
free_rx_dma_descriptor(my_pbuf->dma_descriptor);
LWIP_MEMPOOL_FREE(RX_POOL, my_pbuf);
UNLOCK_INTERRUPTS();
}
void eth_rx_irq()
{
dma_descriptor* dma_desc = get_RX_DMA_descriptor_from_ethernet();
my_custom_pbuf_t* my_pbuf = (my_custom_pbuf_t*)LWIP_MEMPOOL_ALLOC(RX_POOL);
my_pbuf->p.custom_free_function = my_pbuf_free_custom;
my_pbuf->dma_descriptor = dma_desc;
invalidate_cpu_cache(dma_desc->rx_data, dma_desc->rx_length);
struct pbuf* p = pbuf_alloced_custom(PBUF_RAW,
dma_desc->rx_length,
PBUF_REF,
&my_pbuf->p,
dma_desc->rx_data,
dma_desc->max_buffer_size);
if(netif->input(p, netif) != ERR_OK) {
pbuf_free(p);
}
}
@endcode
*/
/*
@@ -117,8 +69,9 @@ void eth_rx_irq()
#include "lwip/memp.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "arch/perf.h"
#if LWIP_TCP && TCP_QUEUE_OOSEQ
#include "lwip/priv/tcp_priv.h"
#include "lwip/tcp_impl.h"
#endif
#if LWIP_CHECKSUM_ON_COPY
#include "lwip/inet_chksum.h"
@@ -139,7 +92,7 @@ void eth_rx_irq()
#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL
#include "lwip/tcpip.h"
#define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL() do { \
if (tcpip_callback_with_block(pbuf_free_ooseq_callback, NULL, 0) != ERR_OK) { \
if(tcpip_callback_with_block(pbuf_free_ooseq_callback, NULL, 0) != ERR_OK) { \
SYS_ARCH_PROTECT(old_level); \
pbuf_free_ooseq_pending = 0; \
SYS_ARCH_UNPROTECT(old_level); \
@@ -165,7 +118,11 @@ void
pbuf_free_ooseq(void)
{
struct tcp_pcb* pcb;
SYS_ARCH_SET(pbuf_free_ooseq_pending, 0);
SYS_ARCH_DECL_PROTECT(old_level);
SYS_ARCH_PROTECT(old_level);
pbuf_free_ooseq_pending = 0;
SYS_ARCH_UNPROTECT(old_level);
for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
if (NULL != pcb->ooseq) {
@@ -180,7 +137,7 @@ pbuf_free_ooseq(void)
#if !NO_SYS
/**
* Just a callback function for tcpip_callback() that calls pbuf_free_ooseq().
* Just a callback function for tcpip_timeout() that calls pbuf_free_ooseq().
*/
static void
pbuf_free_ooseq_callback(void *arg)
@@ -195,7 +152,10 @@ static void
pbuf_pool_is_empty(void)
{
#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL
SYS_ARCH_SET(pbuf_free_ooseq_pending, 1);
SYS_ARCH_DECL_PROTECT(old_level);
SYS_ARCH_PROTECT(old_level);
pbuf_free_ooseq_pending = 1;
SYS_ARCH_UNPROTECT(old_level);
#else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
u8_t queued;
SYS_ARCH_DECL_PROTECT(old_level);
@@ -204,7 +164,7 @@ pbuf_pool_is_empty(void)
pbuf_free_ooseq_pending = 1;
SYS_ARCH_UNPROTECT(old_level);
if (!queued) {
if(!queued) {
/* queue a call to pbuf_free_ooseq if not already queued */
PBUF_POOL_FREE_OOSEQ_QUEUE_CALL();
}
@@ -213,7 +173,6 @@ pbuf_pool_is_empty(void)
#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */
/**
* @ingroup pbuf
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
*
* The actual memory allocated for the pbuf is determined by the
@@ -256,22 +215,17 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
switch (layer) {
case PBUF_TRANSPORT:
/* add room for transport (often TCP) layer header */
offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
break;
case PBUF_IP:
/* add room for IP layer header */
offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN;
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN;
break;
case PBUF_LINK:
/* add room for link layer header */
offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN;
break;
case PBUF_RAW_TX:
/* add room for encapsulating link layer headers (e.g. 802.11) */
offset = PBUF_LINK_ENCAPSULATION_HLEN;
offset = PBUF_LINK_HLEN;
break;
case PBUF_RAW:
/* no offset (e.g. RX buffers or chain successors) */
offset = 0;
break;
default:
@@ -320,7 +274,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
PBUF_POOL_IS_EMPTY();
/* free chain so far allocated */
pbuf_free(p);
/* bail out unsuccessfully */
/* bail out unsuccesfully */
return NULL;
}
q->type = type;
@@ -350,18 +304,8 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
break;
case PBUF_RAM:
{
mem_size_t alloc_len = LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length);
/* bug #50040: Check for integer overflow when calculating alloc_len */
if (alloc_len < LWIP_MEM_ALIGN_SIZE(length)) {
return NULL;
}
/* If pbuf is to be allocated in RAM, allocate memory for it. */
p = (struct pbuf*)mem_malloc(alloc_len);
}
/* If pbuf is to be allocated in RAM, allocate memory for it. */
p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));
if (p == NULL) {
return NULL;
}
@@ -405,11 +349,9 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
}
#if LWIP_SUPPORT_CUSTOM_PBUF
/**
* @ingroup pbuf
* Initialize a custom pbuf (already allocated).
/** Initialize a custom pbuf (already allocated).
*
* @param l flag to define header size
* @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)
@@ -432,19 +374,15 @@ pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_cust
switch (l) {
case PBUF_TRANSPORT:
/* add room for transport (often TCP) layer header */
offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
break;
case PBUF_IP:
/* add room for IP layer header */
offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN;
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN;
break;
case PBUF_LINK:
/* add room for link layer header */
offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN;
break;
case PBUF_RAW_TX:
/* add room for encapsulating link layer headers (e.g. 802.11) */
offset = PBUF_LINK_ENCAPSULATION_HLEN;
offset = PBUF_LINK_HLEN;
break;
case PBUF_RAW:
offset = 0;
@@ -474,7 +412,6 @@ pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_cust
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
/**
* @ingroup pbuf
* Shrink a pbuf chain to a desired length.
*
* @param p pbuf to shrink.
@@ -531,11 +468,7 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
/* shrink allocated memory for PBUF_RAM */
/* (other types merely adjust their length fields */
if ((q->type == PBUF_RAM) && (rem_len != q->len)
#if LWIP_SUPPORT_CUSTOM_PBUF
&& ((q->flags & PBUF_FLAG_IS_CUSTOM) == 0)
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
) {
if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
/* reallocate and adjust the length of the pbuf that will be split */
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);
@@ -556,17 +489,26 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
/**
* Adjusts the payload pointer to hide or reveal headers in the payload.
* @see pbuf_header.
*
* Adjusts the ->payload pointer so that space for a header
* (dis)appears in the pbuf payload.
*
* The ->payload, ->tot_len and ->len fields are adjusted.
*
* @param p pbuf to change the header size.
* @param header_size_increment Number of bytes to increment header size.
* @param force Allow 'header_size_increment > 0' for PBUF_REF/PBUF_ROM types
* @param header_size_increment Number of bytes to increment header size which
* increases the size of the pbuf. New space is on the front.
* (Using a negative value decreases the header size.)
* If hdr_size_inc is 0, this function does nothing and returns succesful.
*
* PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
* the call will fail. A check is made that the increase in header size does
* not move the payload pointer in front of the start of the buffer.
* @return non-zero on failure, zero on success.
*
*/
static u8_t
pbuf_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force)
u8_t
pbuf_header(struct pbuf *p, s16_t header_size_increment)
{
u16_t type;
void *payload;
@@ -576,18 +518,18 @@ pbuf_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force)
if ((header_size_increment == 0) || (p == NULL)) {
return 0;
}
if (header_size_increment < 0) {
increment_magnitude = (u16_t)-header_size_increment;
if (header_size_increment < 0){
increment_magnitude = -header_size_increment;
/* Check that we aren't going to move off the end of the pbuf */
LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
} else {
increment_magnitude = (u16_t)header_size_increment;
increment_magnitude = header_size_increment;
#if 0
/* Can't assert these as some callers speculatively call
pbuf_header() to see if it's OK. Will return 1 below instead. */
/* Check that we've got the correct type of pbuf to work with */
LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",
LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",
p->type == PBUF_RAM || p->type == PBUF_POOL);
/* Check that we aren't going to move off the beginning of the pbuf */
LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",
@@ -605,25 +547,23 @@ pbuf_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force)
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 | LWIP_DBG_TRACE,
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 *)((u8_t *)p + SIZEOF_STRUCT_PBUF)));
(void *)p->payload, (void *)(p + 1)));
/* restore old payload pointer */
p->payload = payload;
/* bail out unsuccessfully */
/* bail out unsuccesfully */
return 1;
}
/* pbuf types referring to external payloads? */
/* pbuf types refering to external payloads? */
} else if (type == PBUF_REF || type == PBUF_ROM) {
/* hide a header in the payload? */
if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {
/* increase payload pointer */
p->payload = (u8_t *)p->payload - header_size_increment;
} else if ((header_size_increment > 0) && force) {
p->payload = (u8_t *)p->payload - header_size_increment;
} else {
/* cannot expand payload to front (yet!)
* bail out unsuccessfully */
* bail out unsuccesfully */
return 1;
}
} else {
@@ -642,43 +582,6 @@ pbuf_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force)
}
/**
* Adjusts the payload pointer to hide or reveal headers in the payload.
*
* Adjusts the ->payload pointer so that space for a header
* (dis)appears in the pbuf payload.
*
* The ->payload, ->tot_len and ->len fields are adjusted.
*
* @param p pbuf to change the header size.
* @param header_size_increment Number of bytes to increment header size which
* increases the size of the pbuf. New space is on the front.
* (Using a negative value decreases the header size.)
* If hdr_size_inc is 0, this function does nothing and returns successful.
*
* PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
* the call will fail. A check is made that the increase in header size does
* not move the payload pointer in front of the start of the buffer.
* @return non-zero on failure, zero on success.
*
*/
u8_t
pbuf_header(struct pbuf *p, s16_t header_size_increment)
{
return pbuf_header_impl(p, header_size_increment, 0);
}
/**
* Same as pbuf_header but does not check if 'header_size > 0' is allowed.
* This is used internally only, to allow PBUF_REF for RX.
*/
u8_t
pbuf_header_force(struct pbuf *p, s16_t header_size_increment)
{
return pbuf_header_impl(p, header_size_increment, 1);
}
/**
* @ingroup pbuf
* Dereference a pbuf chain or queue and deallocate any no-longer-used
* pbufs at the head of this chain or queue.
*
@@ -703,7 +606,7 @@ pbuf_header_force(struct pbuf *p, s16_t header_size_increment)
*
* Assuming existing chains a->b->c with the following reference
* counts, calling pbuf_free(a) results in:
*
*
* 1->2->3 becomes ...1->3
* 3->3->3 becomes 2->3->3
* 1->1->2 becomes ......1
@@ -796,10 +699,11 @@ pbuf_free(struct pbuf *p)
* @param p first pbuf of chain
* @return the number of pbufs in a chain
*/
u16_t
pbuf_clen(const struct pbuf *p)
u8_t
pbuf_clen(struct pbuf *p)
{
u16_t len;
u8_t len;
len = 0;
while (p != NULL) {
@@ -810,7 +714,6 @@ pbuf_clen(const struct pbuf *p)
}
/**
* @ingroup pbuf
* Increment the reference count of the pbuf.
*
* @param p pbuf to increase reference counter of
@@ -819,23 +722,25 @@ pbuf_clen(const struct pbuf *p)
void
pbuf_ref(struct pbuf *p)
{
SYS_ARCH_DECL_PROTECT(old_level);
/* pbuf given? */
if (p != NULL) {
SYS_ARCH_INC(p->ref, 1);
LWIP_ASSERT("pbuf ref overflow", p->ref > 0);
SYS_ARCH_PROTECT(old_level);
++(p->ref);
SYS_ARCH_UNPROTECT(old_level);
}
}
/**
* @ingroup pbuf
* Concatenate two pbufs (each may be a pbuf chain) and take over
* the caller's reference of the tail pbuf.
*
*
* @note The caller MAY NOT reference the tail pbuf afterwards.
* Use pbuf_chain() for that purpose.
*
*
* @see pbuf_chain()
*/
void
pbuf_cat(struct pbuf *h, struct pbuf *t)
{
@@ -862,12 +767,11 @@ pbuf_cat(struct pbuf *h, struct pbuf *t)
}
/**
* @ingroup pbuf
* Chain two pbufs (or pbuf chains) together.
*
*
* The caller MUST call pbuf_free(t) once it has stopped
* using it. Use pbuf_cat() instead if you no longer use t.
*
*
* @param h head pbuf (chain)
* @param t tail pbuf (chain)
* @note The pbufs MUST belong to the same packet.
@@ -927,7 +831,7 @@ pbuf_dechain(struct pbuf *p)
}
/**
* @ingroup pbuf
*
* Create PBUF_RAM copies of pbufs.
*
* Used to queue packets on behalf of the lwIP stack, such as
@@ -945,12 +849,12 @@ pbuf_dechain(struct pbuf *p)
* enough to hold p_from
*/
err_t
pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from)
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, ("pbuf_copy(%p, %p)\n",
(const void*)p_to, (const void*)p_from));
(void*)p_to, (void*)p_from));
/* is the target big enough to hold the source? */
LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
@@ -984,14 +888,14 @@ pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from)
LWIP_ERROR("p_to != NULL", (p_to != NULL) || (p_from == NULL) , return ERR_ARG;);
}
if ((p_from != NULL) && (p_from->len == p_from->tot_len)) {
if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
/* don't copy more than one packet! */
LWIP_ERROR("pbuf_copy() does not allow packet queues!",
LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
(p_from->next == NULL), return ERR_VAL;);
}
if ((p_to != NULL) && (p_to->len == p_to->tot_len)) {
if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
/* don't copy more than one packet! */
LWIP_ERROR("pbuf_copy() does not allow packet queues!",
LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
(p_to->next == NULL), return ERR_VAL;);
}
} while (p_from);
@@ -1000,21 +904,20 @@ pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from)
}
/**
* @ingroup pbuf
* Copy (part of) the contents of a packet buffer
* to an application supplied buffer.
*
* @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). No more
* @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(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
{
const struct pbuf *p;
struct pbuf *p;
u16_t left;
u16_t buf_copy_len;
u16_t copied_total = 0;
@@ -1024,21 +927,20 @@ pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset
left = 0;
if ((buf == NULL) || (dataptr == NULL)) {
if((buf == NULL) || (dataptr == NULL)) {
return 0;
}
/* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
for (p = buf; len != 0 && p != NULL; p = p->next) {
for(p = buf; len != 0 && p != NULL; p = p->next) {
if ((offset != 0) && (offset >= p->len)) {
/* don't copy from this buffer -> on to the next */
offset -= p->len;
} else {
/* copy from this buffer. maybe only partially. */
buf_copy_len = p->len - offset;
if (buf_copy_len > len) {
buf_copy_len = len;
}
if (buf_copy_len > len)
buf_copy_len = len;
/* copy the necessary parts of the buffer */
MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
copied_total += buf_copy_len;
@@ -1050,92 +952,7 @@ pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset
return copied_total;
}
#if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
/**
* This method modifies a 'pbuf chain', so that its total length is
* smaller than 64K. The remainder of the original pbuf chain is stored
* in *rest.
* This function never creates new pbufs, but splits an existing chain
* in two parts. The tot_len of the modified packet queue will likely be
* smaller than 64K.
* 'packet queues' are not supported by this function.
*
* @param p the pbuf queue to be split
* @param rest pointer to store the remainder (after the first 64K)
*/
void pbuf_split_64k(struct pbuf *p, struct pbuf **rest)
{
*rest = NULL;
if ((p != NULL) && (p->next != NULL)) {
u16_t tot_len_front = p->len;
struct pbuf *i = p;
struct pbuf *r = p->next;
/* continue until the total length (summed up as u16_t) overflows */
while ((r != NULL) && ((u16_t)(tot_len_front + r->len) > tot_len_front)) {
tot_len_front += r->len;
i = r;
r = r->next;
}
/* i now points to last packet of the first segment. Set next
pointer to NULL */
i->next = NULL;
if (r != NULL) {
/* Update the tot_len field in the first part */
for (i = p; i != NULL; i = i->next) {
i->tot_len -= r->tot_len;
LWIP_ASSERT("tot_len/len mismatch in last pbuf",
(i->next != NULL) || (i->tot_len == i->len));
}
if (p->flags & PBUF_FLAG_TCP_FIN) {
r->flags |= PBUF_FLAG_TCP_FIN;
}
/* tot_len field in rest does not need modifications */
/* reference counters do not need modifications */
*rest = r;
}
}
}
#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
/* Actual implementation of pbuf_skip() but returning const pointer... */
static const struct pbuf*
pbuf_skip_const(const struct pbuf* in, u16_t in_offset, u16_t* out_offset)
{
u16_t offset_left = in_offset;
const struct pbuf* q = in;
/* get the correct pbuf */
while ((q != NULL) && (q->len <= offset_left)) {
offset_left -= q->len;
q = q->next;
}
if (out_offset != NULL) {
*out_offset = offset_left;
}
return q;
}
/**
* @ingroup pbuf
* Skip a number of bytes at the start of a pbuf
*
* @param in input pbuf
* @param in_offset offset to skip
* @param out_offset resulting offset in the returned pbuf
* @return the pbuf in the queue where the offset is
*/
struct pbuf*
pbuf_skip(struct pbuf* in, u16_t in_offset, u16_t* out_offset)
{
const struct pbuf* out = pbuf_skip_const(in, in_offset, out_offset);
return LWIP_CONST_CAST(struct pbuf*, out);
}
/**
* @ingroup pbuf
* Copy application supplied data into a pbuf.
* This function can only be used to copy the equivalent of buf->tot_len data.
*
@@ -1153,16 +970,15 @@ pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
u16_t total_copy_len = len;
u16_t copied_total = 0;
LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return ERR_ARG;);
LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return ERR_ARG;);
LWIP_ERROR("pbuf_take: buf not large enough", (buf->tot_len >= len), return ERR_MEM;);
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) {
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) {
@@ -1170,7 +986,7 @@ pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
buf_copy_len = p->len;
}
/* copy the necessary parts of the buffer */
MEMCPY(p->payload, &((const char*)dataptr)[copied_total], buf_copy_len);
MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
total_copy_len -= buf_copy_len;
copied_total += buf_copy_len;
}
@@ -1179,41 +995,6 @@ pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
}
/**
* @ingroup pbuf
* Same as pbuf_take() but puts data at an offset
*
* @param buf pbuf to fill with data
* @param dataptr application supplied data buffer
* @param len length of the application supplied data buffer
* @param offset offset in pbuf where to copy dataptr to
*
* @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough
*/
err_t
pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset)
{
u16_t target_offset;
struct pbuf* q = pbuf_skip(buf, offset, &target_offset);
/* return requested data if pbuf is OK */
if ((q != NULL) && (q->tot_len >= target_offset + len)) {
u16_t remaining_len = len;
const u8_t* src_ptr = (const u8_t*)dataptr;
/* copy the part that goes into the first pbuf */
u16_t first_copy_len = LWIP_MIN(q->len - target_offset, len);
MEMCPY(((u8_t*)q->payload) + target_offset, dataptr, first_copy_len);
remaining_len -= first_copy_len;
src_ptr += first_copy_len;
if (remaining_len > 0) {
return pbuf_take(q->next, src_ptr, remaining_len);
}
return ERR_OK;
}
return ERR_MEM;
}
/**
* @ingroup pbuf
* Creates a single pbuf out of a queue of pbufs.
*
* @remark: Either the source pbuf 'p' is freed by this function or the original
@@ -1239,7 +1020,6 @@ pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
return p;
}
err = pbuf_copy(q, p);
LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
pbuf_free(p);
return q;
@@ -1286,9 +1066,7 @@ pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
}
#endif /* LWIP_CHECKSUM_ON_COPY */
/**
* @ingroup pbuf
* Get one byte from the specified position in a pbuf
/** Get one byte from the specified position in a pbuf
* WARNING: returns zero for offset >= p->tot_len
*
* @param p pbuf to parse
@@ -1296,101 +1074,59 @@ pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
* @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len
*/
u8_t
pbuf_get_at(const struct pbuf* p, u16_t offset)
pbuf_get_at(struct pbuf* p, u16_t offset)
{
int ret = pbuf_try_get_at(p, offset);
if (ret >= 0) {
return (u8_t)ret;
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;
}
/**
* @ingroup pbuf
* Get one byte from the specified position in a pbuf
*
* @param p pbuf to parse
* @param offset offset into p of the byte to return
* @return byte at an offset into p [0..0xFF] OR negative if 'offset' >= p->tot_len
*/
int
pbuf_try_get_at(const struct pbuf* p, u16_t offset)
{
u16_t q_idx;
const struct pbuf* q = pbuf_skip_const(p, offset, &q_idx);
/* return requested data if pbuf is OK */
if ((q != NULL) && (q->len > q_idx)) {
return ((u8_t*)q->payload)[q_idx];
}
return -1;
}
/**
* @ingroup pbuf
* Put one byte to the specified position in a pbuf
* WARNING: silently ignores offset >= p->tot_len
*
* @param p pbuf to fill
* @param offset offset into p of the byte to write
* @param data byte to write at an offset into p
*/
void
pbuf_put_at(struct pbuf* p, u16_t offset, u8_t data)
{
u16_t q_idx;
struct pbuf* q = pbuf_skip(p, offset, &q_idx);
/* write requested data if pbuf is OK */
if ((q != NULL) && (q->len > q_idx)) {
((u8_t*)q->payload)[q_idx] = data;
}
}
/**
* @ingroup pbuf
* Compare pbuf contents at specified offset with memory s2, both of length n
/** Compare pbuf contents at specified offset with memory s2, both of length n
*
* @param p pbuf to compare
* @param offset offset into p at which to start comparing
* @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(const struct pbuf* p, u16_t offset, const void* s2, u16_t n)
pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)
{
u16_t start = offset;
const struct pbuf* q = p;
u16_t i;
/* pbuf long enough to perform check? */
if(p->tot_len < (offset + n)) {
return 0xffff;
}
/* get the correct pbuf from chain. We know it succeeds because of p->tot_len check above. */
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 */
for (i = 0; i < n; i++) {
/* We know pbuf_get_at() succeeds because of p->tot_len check above. */
u8_t a = pbuf_get_at(q, start + i);
u8_t b = ((const u8_t*)s2)[i];
if (a != b) {
return i+1;
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 0;
return 0xffff;
}
/**
* @ingroup pbuf
* Find occurrence of mem (with length mem_len) in pbuf p, starting at offset
/** 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
@@ -1401,23 +1137,24 @@ pbuf_memcmp(const struct pbuf* p, u16_t offset, const void* s2, u16_t n)
* @return 0xFFFF if substr was not found in p or the index where it was found
*/
u16_t
pbuf_memfind(const struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)
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; i++) {
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
/** 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!
@@ -1428,7 +1165,7 @@ pbuf_memfind(const struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_o
* @return 0xFFFF if substr was not found in p or the index where it was found
*/
u16_t
pbuf_strstr(const struct pbuf* p, const char* substr)
pbuf_strstr(struct pbuf* p, const char* substr)
{
size_t substr_len;
if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {

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