From af1bc71a9ea09bd92aed033e6a2b6ec2b10c311a Mon Sep 17 00:00:00 2001 From: david gauchard Date: Thu, 9 Jul 2020 18:59:49 +0200 Subject: [PATCH] remove lwip-v1.4 specific code (#7436) * remove lwip-v1.4 specific code * ditto * ditto * fix ip4_addr definition * CI: change debug builds to use IPv6, remove regular IPv6 builds * ditto * split pio CI in four (because they last twice the time of the other builds) * remove option from pio * remove lwIP-1.4 from doc * restore pio CI splitting * fix CI debug6 script * ditto --- .travis.yml | 39 +- boards.txt | 238 -- cores/esp8266/AddrList.h | 2 +- cores/esp8266/Client.h | 2 - cores/esp8266/Esp-version.cpp | 19 - cores/esp8266/IPAddress.cpp | 2 +- cores/esp8266/IPAddress.h | 21 +- cores/esp8266/Udp.h | 4 +- cores/esp8266/sntp-lwip2.cpp | 40 - cores/esp8266/time.cpp | 9 - doc/faq/a05-board-generator.rst | 2 - doc/faq/readme.rst | 5 +- libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp | 9 +- libraries/ESP8266NetBIOS/ESP8266NetBIOS.h | 5 +- .../examples/StaticLease/StaticLease.ino | 16 - .../ESP8266WiFi/src/ESP8266WiFiGeneric.cpp | 15 +- .../ESP8266WiFi/src/ESP8266WiFiGratuitous.cpp | 15 +- libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp | 19 +- libraries/ESP8266WiFi/src/WiFiClient.cpp | 11 - libraries/ESP8266WiFi/src/WiFiServer.cpp | 17 +- .../ESP8266WiFi/src/include/UdpContext.h | 136 +- libraries/ESP8266mDNS/src/LEAmDNS.h | 2 +- libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h | 14 - .../examples/NTP-TZ-DST/NTP-TZ-DST.ino | 3 - tests/debug.sh | 1 - tests/{build1.sh => debug6.sh} | 4 +- tests/run_CI_locally.sh | 9 - tools/boards.txt.py | 30 +- tools/platformio-build.py | 7 +- tools/sdk/include/ipv4_addr.h | 14 +- tools/sdk/include/sntp.h | 4 - tools/sdk/lib/liblwip_gcc.a | Bin 1207642 -> 0 bytes tools/sdk/lwip/include/arch/cc.h | 120 - tools/sdk/lwip/include/arch/perf.h | 40 - tools/sdk/lwip/include/arch/sys_arch.h | 0 tools/sdk/lwip/include/lwip/api.h | 284 -- tools/sdk/lwip/include/lwip/api_msg.h | 174 -- tools/sdk/lwip/include/lwip/app/dhcpserver.h | 114 - tools/sdk/lwip/include/lwip/app/espconn.h | 686 ----- tools/sdk/lwip/include/lwip/app/espconn_buf.h | 60 - tools/sdk/lwip/include/lwip/app/espconn_tcp.h | 55 - tools/sdk/lwip/include/lwip/app/espconn_udp.h | 64 - tools/sdk/lwip/include/lwip/app/ping.h | 85 - tools/sdk/lwip/include/lwip/app/time.h | 53 - tools/sdk/lwip/include/lwip/arch.h | 238 -- tools/sdk/lwip/include/lwip/autoip.h | 119 - tools/sdk/lwip/include/lwip/debug.h | 98 - tools/sdk/lwip/include/lwip/def.h | 127 - tools/sdk/lwip/include/lwip/dhcp.h | 252 -- tools/sdk/lwip/include/lwip/dns.h | 124 - tools/sdk/lwip/include/lwip/err.h | 86 - tools/sdk/lwip/include/lwip/icmp.h | 115 - tools/sdk/lwip/include/lwip/igmp.h | 106 - tools/sdk/lwip/include/lwip/inet.h | 107 - tools/sdk/lwip/include/lwip/inet_chksum.h | 90 - tools/sdk/lwip/include/lwip/init.h | 73 - tools/sdk/lwip/include/lwip/ip.h | 215 -- tools/sdk/lwip/include/lwip/ip_addr.h | 256 -- tools/sdk/lwip/include/lwip/ip_frag.h | 88 - tools/sdk/lwip/include/lwip/mdns.h | 114 - tools/sdk/lwip/include/lwip/mem.h | 143 - tools/sdk/lwip/include/lwip/memp.h | 116 - tools/sdk/lwip/include/lwip/memp_std.h | 126 - tools/sdk/lwip/include/lwip/netbuf.h | 101 - tools/sdk/lwip/include/lwip/netdb.h | 124 - tools/sdk/lwip/include/lwip/netif.h | 320 --- tools/sdk/lwip/include/lwip/netifapi.h | 108 - tools/sdk/lwip/include/lwip/opt.h | 2043 -------------- tools/sdk/lwip/include/lwip/pbuf.h | 160 -- tools/sdk/lwip/include/lwip/puck_def.h | 44 - tools/sdk/lwip/include/lwip/raw.h | 98 - tools/sdk/lwip/include/lwip/sio.h | 141 - tools/sdk/lwip/include/lwip/snmp.h | 367 --- tools/sdk/lwip/include/lwip/snmp_asn1.h | 101 - tools/sdk/lwip/include/lwip/snmp_msg.h | 315 --- tools/sdk/lwip/include/lwip/snmp_structs.h | 268 -- tools/sdk/lwip/include/lwip/sntp.h | 60 - tools/sdk/lwip/include/lwip/sockets.h | 376 --- tools/sdk/lwip/include/lwip/stats.h | 292 -- tools/sdk/lwip/include/lwip/sys.h | 337 --- tools/sdk/lwip/include/lwip/tcp.h | 377 --- tools/sdk/lwip/include/lwip/tcp_impl.h | 492 ---- tools/sdk/lwip/include/lwip/tcpip.h | 159 -- tools/sdk/lwip/include/lwip/timers.h | 98 - tools/sdk/lwip/include/lwip/udp.h | 184 -- tools/sdk/lwip/include/lwipopts.h | 2078 --------------- tools/sdk/lwip/include/netif/etharp.h | 254 -- tools/sdk/lwip/include/netif/if_llc.h | 173 -- tools/sdk/lwip/include/netif/ppp_oe.h | 190 -- tools/sdk/lwip/include/netif/wlan_lwip_if.h | 25 - tools/sdk/lwip/src/Makefile | 40 - tools/sdk/lwip/src/api/api_lib.c | 740 ------ tools/sdk/lwip/src/api/api_msg.c | 1540 ----------- tools/sdk/lwip/src/api/err.c | 75 - tools/sdk/lwip/src/api/netbuf.c | 245 -- tools/sdk/lwip/src/api/netdb.c | 352 --- tools/sdk/lwip/src/api/netifapi.c | 160 -- tools/sdk/lwip/src/api/sockets.c | 2343 ----------------- tools/sdk/lwip/src/api/tcpip.c | 460 ---- tools/sdk/lwip/src/app/dhcpserver.c | 1170 -------- tools/sdk/lwip/src/app/espconn.c | 1347 ---------- tools/sdk/lwip/src/app/espconn_buf.c | 205 -- tools/sdk/lwip/src/app/espconn_mdns.c | 134 - tools/sdk/lwip/src/app/espconn_tcp.c | 1479 ----------- tools/sdk/lwip/src/app/espconn_udp.c | 424 --- tools/sdk/lwip/src/app/netio.c | 369 --- tools/sdk/lwip/src/app/ping.c | 329 --- tools/sdk/lwip/src/core/def.c | 108 - tools/sdk/lwip/src/core/dhcp.c | 1815 ------------- tools/sdk/lwip/src/core/dns.c | 988 ------- tools/sdk/lwip/src/core/init.c | 325 --- tools/sdk/lwip/src/core/ipv4/autoip.c | 536 ---- tools/sdk/lwip/src/core/ipv4/icmp.c | 338 --- tools/sdk/lwip/src/core/ipv4/igmp.c | 832 ------ tools/sdk/lwip/src/core/ipv4/inet.c | 42 - tools/sdk/lwip/src/core/ipv4/inet_chksum.c | 450 ---- tools/sdk/lwip/src/core/ipv4/ip.c | 910 ------- tools/sdk/lwip/src/core/ipv4/ip_addr.c | 329 --- tools/sdk/lwip/src/core/ipv4/ip_frag.c | 863 ------ tools/sdk/lwip/src/core/mdns.c | 1137 -------- tools/sdk/lwip/src/core/mem.c | 644 ----- tools/sdk/lwip/src/core/memp.c | 490 ---- tools/sdk/lwip/src/core/netif.c | 762 ------ tools/sdk/lwip/src/core/pbuf.c | 1257 --------- tools/sdk/lwip/src/core/raw.c | 358 --- tools/sdk/lwip/src/core/sntp.c | 1185 --------- tools/sdk/lwip/src/core/stats.c | 176 -- tools/sdk/lwip/src/core/sys.c | 66 - tools/sdk/lwip/src/core/sys_arch.c | 13 - tools/sdk/lwip/src/core/tcp.c | 1673 ------------ tools/sdk/lwip/src/core/tcp_in.c | 1646 ------------ tools/sdk/lwip/src/core/tcp_out.c | 1525 ----------- tools/sdk/lwip/src/core/timers.c | 513 ---- tools/sdk/lwip/src/core/udp.c | 989 ------- tools/sdk/lwip/src/netif/etharp.c | 1413 ---------- 135 files changed, 49 insertions(+), 47073 deletions(-) rename tests/{build1.sh => debug6.sh} (80%) delete mode 100644 tools/sdk/lib/liblwip_gcc.a delete mode 100644 tools/sdk/lwip/include/arch/cc.h delete mode 100644 tools/sdk/lwip/include/arch/perf.h delete mode 100644 tools/sdk/lwip/include/arch/sys_arch.h delete mode 100644 tools/sdk/lwip/include/lwip/api.h delete mode 100644 tools/sdk/lwip/include/lwip/api_msg.h delete mode 100644 tools/sdk/lwip/include/lwip/app/dhcpserver.h delete mode 100644 tools/sdk/lwip/include/lwip/app/espconn.h delete mode 100644 tools/sdk/lwip/include/lwip/app/espconn_buf.h delete mode 100644 tools/sdk/lwip/include/lwip/app/espconn_tcp.h delete mode 100644 tools/sdk/lwip/include/lwip/app/espconn_udp.h delete mode 100644 tools/sdk/lwip/include/lwip/app/ping.h delete mode 100644 tools/sdk/lwip/include/lwip/app/time.h delete mode 100644 tools/sdk/lwip/include/lwip/arch.h delete mode 100644 tools/sdk/lwip/include/lwip/autoip.h delete mode 100644 tools/sdk/lwip/include/lwip/debug.h delete mode 100644 tools/sdk/lwip/include/lwip/def.h delete mode 100644 tools/sdk/lwip/include/lwip/dhcp.h delete mode 100644 tools/sdk/lwip/include/lwip/dns.h delete mode 100644 tools/sdk/lwip/include/lwip/err.h delete mode 100644 tools/sdk/lwip/include/lwip/icmp.h delete mode 100644 tools/sdk/lwip/include/lwip/igmp.h delete mode 100644 tools/sdk/lwip/include/lwip/inet.h delete mode 100644 tools/sdk/lwip/include/lwip/inet_chksum.h delete mode 100644 tools/sdk/lwip/include/lwip/init.h delete mode 100644 tools/sdk/lwip/include/lwip/ip.h delete mode 100644 tools/sdk/lwip/include/lwip/ip_addr.h delete mode 100644 tools/sdk/lwip/include/lwip/ip_frag.h delete mode 100644 tools/sdk/lwip/include/lwip/mdns.h delete mode 100644 tools/sdk/lwip/include/lwip/mem.h delete mode 100644 tools/sdk/lwip/include/lwip/memp.h delete mode 100644 tools/sdk/lwip/include/lwip/memp_std.h delete mode 100644 tools/sdk/lwip/include/lwip/netbuf.h delete mode 100644 tools/sdk/lwip/include/lwip/netdb.h delete mode 100644 tools/sdk/lwip/include/lwip/netif.h delete mode 100644 tools/sdk/lwip/include/lwip/netifapi.h delete mode 100644 tools/sdk/lwip/include/lwip/opt.h delete mode 100644 tools/sdk/lwip/include/lwip/pbuf.h delete mode 100644 tools/sdk/lwip/include/lwip/puck_def.h delete mode 100644 tools/sdk/lwip/include/lwip/raw.h delete mode 100644 tools/sdk/lwip/include/lwip/sio.h delete mode 100644 tools/sdk/lwip/include/lwip/snmp.h delete mode 100644 tools/sdk/lwip/include/lwip/snmp_asn1.h delete mode 100644 tools/sdk/lwip/include/lwip/snmp_msg.h delete mode 100644 tools/sdk/lwip/include/lwip/snmp_structs.h delete mode 100644 tools/sdk/lwip/include/lwip/sntp.h delete mode 100644 tools/sdk/lwip/include/lwip/sockets.h delete mode 100644 tools/sdk/lwip/include/lwip/stats.h delete mode 100644 tools/sdk/lwip/include/lwip/sys.h delete mode 100644 tools/sdk/lwip/include/lwip/tcp.h delete mode 100644 tools/sdk/lwip/include/lwip/tcp_impl.h delete mode 100644 tools/sdk/lwip/include/lwip/tcpip.h delete mode 100644 tools/sdk/lwip/include/lwip/timers.h delete mode 100644 tools/sdk/lwip/include/lwip/udp.h delete mode 100644 tools/sdk/lwip/include/lwipopts.h delete mode 100644 tools/sdk/lwip/include/netif/etharp.h delete mode 100644 tools/sdk/lwip/include/netif/if_llc.h delete mode 100644 tools/sdk/lwip/include/netif/ppp_oe.h delete mode 100644 tools/sdk/lwip/include/netif/wlan_lwip_if.h delete mode 100644 tools/sdk/lwip/src/Makefile delete mode 100644 tools/sdk/lwip/src/api/api_lib.c delete mode 100644 tools/sdk/lwip/src/api/api_msg.c delete mode 100644 tools/sdk/lwip/src/api/err.c delete mode 100644 tools/sdk/lwip/src/api/netbuf.c delete mode 100644 tools/sdk/lwip/src/api/netdb.c delete mode 100644 tools/sdk/lwip/src/api/netifapi.c delete mode 100644 tools/sdk/lwip/src/api/sockets.c delete mode 100644 tools/sdk/lwip/src/api/tcpip.c delete mode 100644 tools/sdk/lwip/src/app/dhcpserver.c delete mode 100644 tools/sdk/lwip/src/app/espconn.c delete mode 100644 tools/sdk/lwip/src/app/espconn_buf.c delete mode 100644 tools/sdk/lwip/src/app/espconn_mdns.c delete mode 100644 tools/sdk/lwip/src/app/espconn_tcp.c delete mode 100644 tools/sdk/lwip/src/app/espconn_udp.c delete mode 100644 tools/sdk/lwip/src/app/netio.c delete mode 100644 tools/sdk/lwip/src/app/ping.c delete mode 100644 tools/sdk/lwip/src/core/def.c delete mode 100755 tools/sdk/lwip/src/core/dhcp.c delete mode 100755 tools/sdk/lwip/src/core/dns.c delete mode 100644 tools/sdk/lwip/src/core/init.c delete mode 100644 tools/sdk/lwip/src/core/ipv4/autoip.c delete mode 100644 tools/sdk/lwip/src/core/ipv4/icmp.c delete mode 100644 tools/sdk/lwip/src/core/ipv4/igmp.c delete mode 100644 tools/sdk/lwip/src/core/ipv4/inet.c delete mode 100644 tools/sdk/lwip/src/core/ipv4/inet_chksum.c delete mode 100644 tools/sdk/lwip/src/core/ipv4/ip.c delete mode 100644 tools/sdk/lwip/src/core/ipv4/ip_addr.c delete mode 100644 tools/sdk/lwip/src/core/ipv4/ip_frag.c delete mode 100644 tools/sdk/lwip/src/core/mdns.c delete mode 100644 tools/sdk/lwip/src/core/mem.c delete mode 100644 tools/sdk/lwip/src/core/memp.c delete mode 100644 tools/sdk/lwip/src/core/netif.c delete mode 100644 tools/sdk/lwip/src/core/pbuf.c delete mode 100644 tools/sdk/lwip/src/core/raw.c delete mode 100755 tools/sdk/lwip/src/core/sntp.c delete mode 100644 tools/sdk/lwip/src/core/stats.c delete mode 100644 tools/sdk/lwip/src/core/sys.c delete mode 100644 tools/sdk/lwip/src/core/sys_arch.c delete mode 100644 tools/sdk/lwip/src/core/tcp.c delete mode 100644 tools/sdk/lwip/src/core/tcp_in.c delete mode 100644 tools/sdk/lwip/src/core/tcp_out.c delete mode 100644 tools/sdk/lwip/src/core/timers.c delete mode 100644 tools/sdk/lwip/src/core/udp.c delete mode 100644 tools/sdk/lwip/src/netif/etharp.c diff --git a/.travis.yml b/.travis.yml index c187c2712..ac282d540 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,38 +47,27 @@ jobs: env: - BUILD_PARITY=odd - - name: "Debug (1)" + - name: "Debug IPv6 (1)" stage: build - script: $TRAVIS_BUILD_DIR/tests/debug.sh + script: $TRAVIS_BUILD_DIR/tests/debug6.sh env: - BUILD_PARITY=even - - name: "Debug (2)" + - name: "Debug IPv6 (2)" stage: build - script: $TRAVIS_BUILD_DIR/tests/debug.sh + script: $TRAVIS_BUILD_DIR/tests/debug6.sh env: - BUILD_PARITY=odd - - name: "Build IPv6 (1)" - stage: build - script: $TRAVIS_BUILD_DIR/tests/build6.sh - env: - - BUILD_PARITY=even - - name: "Build IPv6 (2)" - stage: build - script: $TRAVIS_BUILD_DIR/tests/build6.sh - env: - - BUILD_PARITY=odd - - - name: "Build lwIP-v1.4 (1)" - stage: build - script: $TRAVIS_BUILD_DIR/tests/build1.sh - env: - - BUILD_PARITY=even - - name: "Build lwIP-v1.4 (2)" - stage: build - script: $TRAVIS_BUILD_DIR/tests/build1.sh - env: - - BUILD_PARITY=odd +# - name: "Build IPv6 (1)" +# stage: build +# script: $TRAVIS_BUILD_DIR/tests/build6.sh +# env: +# - BUILD_PARITY=even +# - name: "Build IPv6 (2)" +# stage: build +# script: $TRAVIS_BUILD_DIR/tests/build6.sh +# env: +# - BUILD_PARITY=odd - name: "Mac OSX can build sketches" os: osx diff --git a/boards.txt b/boards.txt index 19a22b5db..ba4c7e6e0 100644 --- a/boards.txt +++ b/boards.txt @@ -413,13 +413,6 @@ generic.menu.ip.hb6f=v2 IPv6 Higher Bandwidth generic.menu.ip.hb6f.build.lwip_include=lwip2/include generic.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat generic.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -generic.menu.ip.hb1=v1.4 Higher Bandwidth -generic.menu.ip.hb1.build.lwip_lib=-llwip_gcc -generic.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -generic.menu.ip.src=v1.4 Compile from source -generic.menu.ip.src.build.lwip_lib=-llwip_src -generic.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -generic.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" generic.menu.dbg.Disabled=Disabled generic.menu.dbg.Disabled.build.debug_port= generic.menu.dbg.Serial=Serial @@ -749,13 +742,6 @@ esp8285.menu.ip.hb6f=v2 IPv6 Higher Bandwidth esp8285.menu.ip.hb6f.build.lwip_include=lwip2/include esp8285.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat esp8285.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -esp8285.menu.ip.hb1=v1.4 Higher Bandwidth -esp8285.menu.ip.hb1.build.lwip_lib=-llwip_gcc -esp8285.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -esp8285.menu.ip.src=v1.4 Compile from source -esp8285.menu.ip.src.build.lwip_lib=-llwip_src -esp8285.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -esp8285.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" esp8285.menu.dbg.Disabled=Disabled esp8285.menu.dbg.Disabled.build.debug_port= esp8285.menu.dbg.Serial=Serial @@ -954,13 +940,6 @@ espduino.menu.ip.hb6f=v2 IPv6 Higher Bandwidth espduino.menu.ip.hb6f.build.lwip_include=lwip2/include espduino.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat espduino.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -espduino.menu.ip.hb1=v1.4 Higher Bandwidth -espduino.menu.ip.hb1.build.lwip_lib=-llwip_gcc -espduino.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -espduino.menu.ip.src=v1.4 Compile from source -espduino.menu.ip.src.build.lwip_lib=-llwip_src -espduino.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -espduino.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" espduino.menu.dbg.Disabled=Disabled espduino.menu.dbg.Disabled.build.debug_port= espduino.menu.dbg.Serial=Serial @@ -1151,13 +1130,6 @@ huzzah.menu.ip.hb6f=v2 IPv6 Higher Bandwidth huzzah.menu.ip.hb6f.build.lwip_include=lwip2/include huzzah.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat huzzah.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -huzzah.menu.ip.hb1=v1.4 Higher Bandwidth -huzzah.menu.ip.hb1.build.lwip_lib=-llwip_gcc -huzzah.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -huzzah.menu.ip.src=v1.4 Compile from source -huzzah.menu.ip.src.build.lwip_lib=-llwip_src -huzzah.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -huzzah.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" huzzah.menu.dbg.Disabled=Disabled huzzah.menu.dbg.Disabled.build.debug_port= huzzah.menu.dbg.Serial=Serial @@ -1348,13 +1320,6 @@ inventone.menu.ip.hb6f=v2 IPv6 Higher Bandwidth inventone.menu.ip.hb6f.build.lwip_include=lwip2/include inventone.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat inventone.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -inventone.menu.ip.hb1=v1.4 Higher Bandwidth -inventone.menu.ip.hb1.build.lwip_lib=-llwip_gcc -inventone.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -inventone.menu.ip.src=v1.4 Compile from source -inventone.menu.ip.src.build.lwip_lib=-llwip_src -inventone.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -inventone.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" inventone.menu.dbg.Disabled=Disabled inventone.menu.dbg.Disabled.build.debug_port= inventone.menu.dbg.Serial=Serial @@ -1548,13 +1513,6 @@ cw01.menu.ip.hb6f=v2 IPv6 Higher Bandwidth cw01.menu.ip.hb6f.build.lwip_include=lwip2/include cw01.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat cw01.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -cw01.menu.ip.hb1=v1.4 Higher Bandwidth -cw01.menu.ip.hb1.build.lwip_lib=-llwip_gcc -cw01.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -cw01.menu.ip.src=v1.4 Compile from source -cw01.menu.ip.src.build.lwip_lib=-llwip_src -cw01.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -cw01.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" cw01.menu.dbg.Disabled=Disabled cw01.menu.dbg.Disabled.build.debug_port= cw01.menu.dbg.Serial=Serial @@ -1748,13 +1706,6 @@ espresso_lite_v1.menu.ip.hb6f=v2 IPv6 Higher Bandwidth espresso_lite_v1.menu.ip.hb6f.build.lwip_include=lwip2/include espresso_lite_v1.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat espresso_lite_v1.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -espresso_lite_v1.menu.ip.hb1=v1.4 Higher Bandwidth -espresso_lite_v1.menu.ip.hb1.build.lwip_lib=-llwip_gcc -espresso_lite_v1.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -espresso_lite_v1.menu.ip.src=v1.4 Compile from source -espresso_lite_v1.menu.ip.src.build.lwip_lib=-llwip_src -espresso_lite_v1.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -espresso_lite_v1.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" espresso_lite_v1.menu.dbg.Disabled=Disabled espresso_lite_v1.menu.dbg.Disabled.build.debug_port= espresso_lite_v1.menu.dbg.Serial=Serial @@ -1948,13 +1899,6 @@ espresso_lite_v2.menu.ip.hb6f=v2 IPv6 Higher Bandwidth espresso_lite_v2.menu.ip.hb6f.build.lwip_include=lwip2/include espresso_lite_v2.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat espresso_lite_v2.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -espresso_lite_v2.menu.ip.hb1=v1.4 Higher Bandwidth -espresso_lite_v2.menu.ip.hb1.build.lwip_lib=-llwip_gcc -espresso_lite_v2.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -espresso_lite_v2.menu.ip.src=v1.4 Compile from source -espresso_lite_v2.menu.ip.src.build.lwip_lib=-llwip_src -espresso_lite_v2.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -espresso_lite_v2.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" espresso_lite_v2.menu.dbg.Disabled=Disabled espresso_lite_v2.menu.dbg.Disabled.build.debug_port= espresso_lite_v2.menu.dbg.Serial=Serial @@ -2148,13 +2092,6 @@ phoenix_v1.menu.ip.hb6f=v2 IPv6 Higher Bandwidth phoenix_v1.menu.ip.hb6f.build.lwip_include=lwip2/include phoenix_v1.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat phoenix_v1.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -phoenix_v1.menu.ip.hb1=v1.4 Higher Bandwidth -phoenix_v1.menu.ip.hb1.build.lwip_lib=-llwip_gcc -phoenix_v1.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -phoenix_v1.menu.ip.src=v1.4 Compile from source -phoenix_v1.menu.ip.src.build.lwip_lib=-llwip_src -phoenix_v1.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -phoenix_v1.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" phoenix_v1.menu.dbg.Disabled=Disabled phoenix_v1.menu.dbg.Disabled.build.debug_port= phoenix_v1.menu.dbg.Serial=Serial @@ -2348,13 +2285,6 @@ phoenix_v2.menu.ip.hb6f=v2 IPv6 Higher Bandwidth phoenix_v2.menu.ip.hb6f.build.lwip_include=lwip2/include phoenix_v2.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat phoenix_v2.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -phoenix_v2.menu.ip.hb1=v1.4 Higher Bandwidth -phoenix_v2.menu.ip.hb1.build.lwip_lib=-llwip_gcc -phoenix_v2.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -phoenix_v2.menu.ip.src=v1.4 Compile from source -phoenix_v2.menu.ip.src.build.lwip_lib=-llwip_src -phoenix_v2.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -phoenix_v2.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" phoenix_v2.menu.dbg.Disabled=Disabled phoenix_v2.menu.dbg.Disabled.build.debug_port= phoenix_v2.menu.dbg.Serial=Serial @@ -2545,13 +2475,6 @@ nodemcu.menu.ip.hb6f=v2 IPv6 Higher Bandwidth nodemcu.menu.ip.hb6f.build.lwip_include=lwip2/include nodemcu.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat nodemcu.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -nodemcu.menu.ip.hb1=v1.4 Higher Bandwidth -nodemcu.menu.ip.hb1.build.lwip_lib=-llwip_gcc -nodemcu.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -nodemcu.menu.ip.src=v1.4 Compile from source -nodemcu.menu.ip.src.build.lwip_lib=-llwip_src -nodemcu.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -nodemcu.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" nodemcu.menu.dbg.Disabled=Disabled nodemcu.menu.dbg.Disabled.build.debug_port= nodemcu.menu.dbg.Serial=Serial @@ -2746,13 +2669,6 @@ nodemcuv2.menu.ip.hb6f=v2 IPv6 Higher Bandwidth nodemcuv2.menu.ip.hb6f.build.lwip_include=lwip2/include nodemcuv2.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat nodemcuv2.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -nodemcuv2.menu.ip.hb1=v1.4 Higher Bandwidth -nodemcuv2.menu.ip.hb1.build.lwip_lib=-llwip_gcc -nodemcuv2.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -nodemcuv2.menu.ip.src=v1.4 Compile from source -nodemcuv2.menu.ip.src.build.lwip_lib=-llwip_src -nodemcuv2.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -nodemcuv2.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" nodemcuv2.menu.dbg.Disabled=Disabled nodemcuv2.menu.dbg.Disabled.build.debug_port= nodemcuv2.menu.dbg.Serial=Serial @@ -2963,13 +2879,6 @@ modwifi.menu.ip.hb6f=v2 IPv6 Higher Bandwidth modwifi.menu.ip.hb6f.build.lwip_include=lwip2/include modwifi.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat modwifi.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -modwifi.menu.ip.hb1=v1.4 Higher Bandwidth -modwifi.menu.ip.hb1.build.lwip_lib=-llwip_gcc -modwifi.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -modwifi.menu.ip.src=v1.4 Compile from source -modwifi.menu.ip.src.build.lwip_lib=-llwip_src -modwifi.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -modwifi.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" modwifi.menu.dbg.Disabled=Disabled modwifi.menu.dbg.Disabled.build.debug_port= modwifi.menu.dbg.Serial=Serial @@ -3160,13 +3069,6 @@ thing.menu.ip.hb6f=v2 IPv6 Higher Bandwidth thing.menu.ip.hb6f.build.lwip_include=lwip2/include thing.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat thing.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -thing.menu.ip.hb1=v1.4 Higher Bandwidth -thing.menu.ip.hb1.build.lwip_lib=-llwip_gcc -thing.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -thing.menu.ip.src=v1.4 Compile from source -thing.menu.ip.src.build.lwip_lib=-llwip_src -thing.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -thing.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" thing.menu.dbg.Disabled=Disabled thing.menu.dbg.Disabled.build.debug_port= thing.menu.dbg.Serial=Serial @@ -3357,13 +3259,6 @@ thingdev.menu.ip.hb6f=v2 IPv6 Higher Bandwidth thingdev.menu.ip.hb6f.build.lwip_include=lwip2/include thingdev.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat thingdev.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -thingdev.menu.ip.hb1=v1.4 Higher Bandwidth -thingdev.menu.ip.hb1.build.lwip_lib=-llwip_gcc -thingdev.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -thingdev.menu.ip.src=v1.4 Compile from source -thingdev.menu.ip.src.build.lwip_lib=-llwip_src -thingdev.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -thingdev.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" thingdev.menu.dbg.Disabled=Disabled thingdev.menu.dbg.Disabled.build.debug_port= thingdev.menu.dbg.Serial=Serial @@ -3554,13 +3449,6 @@ blynk.menu.ip.hb6f=v2 IPv6 Higher Bandwidth blynk.menu.ip.hb6f.build.lwip_include=lwip2/include blynk.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat blynk.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -blynk.menu.ip.hb1=v1.4 Higher Bandwidth -blynk.menu.ip.hb1.build.lwip_lib=-llwip_gcc -blynk.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -blynk.menu.ip.src=v1.4 Compile from source -blynk.menu.ip.src.build.lwip_lib=-llwip_src -blynk.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -blynk.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" blynk.menu.dbg.Disabled=Disabled blynk.menu.dbg.Disabled.build.debug_port= blynk.menu.dbg.Serial=Serial @@ -3751,13 +3639,6 @@ esp210.menu.ip.hb6f=v2 IPv6 Higher Bandwidth esp210.menu.ip.hb6f.build.lwip_include=lwip2/include esp210.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat esp210.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -esp210.menu.ip.hb1=v1.4 Higher Bandwidth -esp210.menu.ip.hb1.build.lwip_lib=-llwip_gcc -esp210.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -esp210.menu.ip.src=v1.4 Compile from source -esp210.menu.ip.src.build.lwip_lib=-llwip_src -esp210.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -esp210.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" esp210.menu.dbg.Disabled=Disabled esp210.menu.dbg.Disabled.build.debug_port= esp210.menu.dbg.Serial=Serial @@ -3948,13 +3829,6 @@ d1_mini.menu.ip.hb6f=v2 IPv6 Higher Bandwidth d1_mini.menu.ip.hb6f.build.lwip_include=lwip2/include d1_mini.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat d1_mini.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -d1_mini.menu.ip.hb1=v1.4 Higher Bandwidth -d1_mini.menu.ip.hb1.build.lwip_lib=-llwip_gcc -d1_mini.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -d1_mini.menu.ip.src=v1.4 Compile from source -d1_mini.menu.ip.src.build.lwip_lib=-llwip_src -d1_mini.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -d1_mini.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" d1_mini.menu.dbg.Disabled=Disabled d1_mini.menu.dbg.Disabled.build.debug_port= d1_mini.menu.dbg.Serial=Serial @@ -4128,13 +4002,6 @@ d1_mini_pro.menu.ip.hb6f=v2 IPv6 Higher Bandwidth d1_mini_pro.menu.ip.hb6f.build.lwip_include=lwip2/include d1_mini_pro.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat d1_mini_pro.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -d1_mini_pro.menu.ip.hb1=v1.4 Higher Bandwidth -d1_mini_pro.menu.ip.hb1.build.lwip_lib=-llwip_gcc -d1_mini_pro.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -d1_mini_pro.menu.ip.src=v1.4 Compile from source -d1_mini_pro.menu.ip.src.build.lwip_lib=-llwip_src -d1_mini_pro.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -d1_mini_pro.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" d1_mini_pro.menu.dbg.Disabled=Disabled d1_mini_pro.menu.dbg.Disabled.build.debug_port= d1_mini_pro.menu.dbg.Serial=Serial @@ -4365,13 +4232,6 @@ d1_mini_lite.menu.ip.hb6f=v2 IPv6 Higher Bandwidth d1_mini_lite.menu.ip.hb6f.build.lwip_include=lwip2/include d1_mini_lite.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat d1_mini_lite.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -d1_mini_lite.menu.ip.hb1=v1.4 Higher Bandwidth -d1_mini_lite.menu.ip.hb1.build.lwip_lib=-llwip_gcc -d1_mini_lite.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -d1_mini_lite.menu.ip.src=v1.4 Compile from source -d1_mini_lite.menu.ip.src.build.lwip_lib=-llwip_src -d1_mini_lite.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -d1_mini_lite.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" d1_mini_lite.menu.dbg.Disabled=Disabled d1_mini_lite.menu.dbg.Disabled.build.debug_port= d1_mini_lite.menu.dbg.Serial=Serial @@ -4562,13 +4422,6 @@ d1.menu.ip.hb6f=v2 IPv6 Higher Bandwidth d1.menu.ip.hb6f.build.lwip_include=lwip2/include d1.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat d1.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -d1.menu.ip.hb1=v1.4 Higher Bandwidth -d1.menu.ip.hb1.build.lwip_lib=-llwip_gcc -d1.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -d1.menu.ip.src=v1.4 Compile from source -d1.menu.ip.src.build.lwip_lib=-llwip_src -d1.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -d1.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" d1.menu.dbg.Disabled=Disabled d1.menu.dbg.Disabled.build.debug_port= d1.menu.dbg.Serial=Serial @@ -4762,13 +4615,6 @@ espino.menu.ip.hb6f=v2 IPv6 Higher Bandwidth espino.menu.ip.hb6f.build.lwip_include=lwip2/include espino.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat espino.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -espino.menu.ip.hb1=v1.4 Higher Bandwidth -espino.menu.ip.hb1.build.lwip_lib=-llwip_gcc -espino.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -espino.menu.ip.src=v1.4 Compile from source -espino.menu.ip.src.build.lwip_lib=-llwip_src -espino.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -espino.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" espino.menu.dbg.Disabled=Disabled espino.menu.dbg.Disabled.build.debug_port= espino.menu.dbg.Serial=Serial @@ -4959,13 +4805,6 @@ espinotee.menu.ip.hb6f=v2 IPv6 Higher Bandwidth espinotee.menu.ip.hb6f.build.lwip_include=lwip2/include espinotee.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat espinotee.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -espinotee.menu.ip.hb1=v1.4 Higher Bandwidth -espinotee.menu.ip.hb1.build.lwip_lib=-llwip_gcc -espinotee.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -espinotee.menu.ip.src=v1.4 Compile from source -espinotee.menu.ip.src.build.lwip_lib=-llwip_src -espinotee.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -espinotee.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" espinotee.menu.dbg.Disabled=Disabled espinotee.menu.dbg.Disabled.build.debug_port= espinotee.menu.dbg.Serial=Serial @@ -5220,13 +5059,6 @@ wifinfo.menu.ip.hb6f=v2 IPv6 Higher Bandwidth wifinfo.menu.ip.hb6f.build.lwip_include=lwip2/include wifinfo.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat wifinfo.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -wifinfo.menu.ip.hb1=v1.4 Higher Bandwidth -wifinfo.menu.ip.hb1.build.lwip_lib=-llwip_gcc -wifinfo.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -wifinfo.menu.ip.src=v1.4 Compile from source -wifinfo.menu.ip.src.build.lwip_lib=-llwip_src -wifinfo.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -wifinfo.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" wifinfo.menu.dbg.Disabled=Disabled wifinfo.menu.dbg.Disabled.build.debug_port= wifinfo.menu.dbg.Serial=Serial @@ -5429,13 +5261,6 @@ arduino-esp8266.menu.ip.hb6f=v2 IPv6 Higher Bandwidth arduino-esp8266.menu.ip.hb6f.build.lwip_include=lwip2/include arduino-esp8266.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat arduino-esp8266.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -arduino-esp8266.menu.ip.hb1=v1.4 Higher Bandwidth -arduino-esp8266.menu.ip.hb1.build.lwip_lib=-llwip_gcc -arduino-esp8266.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -arduino-esp8266.menu.ip.src=v1.4 Compile from source -arduino-esp8266.menu.ip.src.build.lwip_lib=-llwip_src -arduino-esp8266.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -arduino-esp8266.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" arduino-esp8266.menu.dbg.Disabled=Disabled arduino-esp8266.menu.dbg.Disabled.build.debug_port= arduino-esp8266.menu.dbg.Serial=Serial @@ -5694,13 +5519,6 @@ gen4iod.menu.ip.hb6f=v2 IPv6 Higher Bandwidth gen4iod.menu.ip.hb6f.build.lwip_include=lwip2/include gen4iod.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat gen4iod.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -gen4iod.menu.ip.hb1=v1.4 Higher Bandwidth -gen4iod.menu.ip.hb1.build.lwip_lib=-llwip_gcc -gen4iod.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -gen4iod.menu.ip.src=v1.4 Compile from source -gen4iod.menu.ip.src.build.lwip_lib=-llwip_src -gen4iod.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -gen4iod.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" gen4iod.menu.dbg.Disabled=Disabled gen4iod.menu.dbg.Disabled.build.debug_port= gen4iod.menu.dbg.Serial=Serial @@ -5892,13 +5710,6 @@ oak.menu.ip.hb6f=v2 IPv6 Higher Bandwidth oak.menu.ip.hb6f.build.lwip_include=lwip2/include oak.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat oak.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -oak.menu.ip.hb1=v1.4 Higher Bandwidth -oak.menu.ip.hb1.build.lwip_lib=-llwip_gcc -oak.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -oak.menu.ip.src=v1.4 Compile from source -oak.menu.ip.src.build.lwip_lib=-llwip_src -oak.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -oak.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" oak.menu.dbg.Disabled=Disabled oak.menu.dbg.Disabled.build.debug_port= oak.menu.dbg.Serial=Serial @@ -6089,13 +5900,6 @@ wifiduino.menu.ip.hb6f=v2 IPv6 Higher Bandwidth wifiduino.menu.ip.hb6f.build.lwip_include=lwip2/include wifiduino.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat wifiduino.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -wifiduino.menu.ip.hb1=v1.4 Higher Bandwidth -wifiduino.menu.ip.hb1.build.lwip_lib=-llwip_gcc -wifiduino.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -wifiduino.menu.ip.src=v1.4 Compile from source -wifiduino.menu.ip.src.build.lwip_lib=-llwip_src -wifiduino.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -wifiduino.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" wifiduino.menu.dbg.Disabled=Disabled wifiduino.menu.dbg.Disabled.build.debug_port= wifiduino.menu.dbg.Serial=Serial @@ -6400,13 +6204,6 @@ wifi_slot.menu.ip.hb6f=v2 IPv6 Higher Bandwidth wifi_slot.menu.ip.hb6f.build.lwip_include=lwip2/include wifi_slot.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat wifi_slot.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -wifi_slot.menu.ip.hb1=v1.4 Higher Bandwidth -wifi_slot.menu.ip.hb1.build.lwip_lib=-llwip_gcc -wifi_slot.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -wifi_slot.menu.ip.src=v1.4 Compile from source -wifi_slot.menu.ip.src.build.lwip_lib=-llwip_src -wifi_slot.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -wifi_slot.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" wifi_slot.menu.dbg.Disabled=Disabled wifi_slot.menu.dbg.Disabled.build.debug_port= wifi_slot.menu.dbg.Serial=Serial @@ -6597,13 +6394,6 @@ wiolink.menu.ip.hb6f=v2 IPv6 Higher Bandwidth wiolink.menu.ip.hb6f.build.lwip_include=lwip2/include wiolink.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat wiolink.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -wiolink.menu.ip.hb1=v1.4 Higher Bandwidth -wiolink.menu.ip.hb1.build.lwip_lib=-llwip_gcc -wiolink.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -wiolink.menu.ip.src=v1.4 Compile from source -wiolink.menu.ip.src.build.lwip_lib=-llwip_src -wiolink.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -wiolink.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" wiolink.menu.dbg.Disabled=Disabled wiolink.menu.dbg.Disabled.build.debug_port= wiolink.menu.dbg.Serial=Serial @@ -6794,13 +6584,6 @@ espectro.menu.ip.hb6f=v2 IPv6 Higher Bandwidth espectro.menu.ip.hb6f.build.lwip_include=lwip2/include espectro.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat espectro.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -espectro.menu.ip.hb1=v1.4 Higher Bandwidth -espectro.menu.ip.hb1.build.lwip_lib=-llwip_gcc -espectro.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -espectro.menu.ip.src=v1.4 Compile from source -espectro.menu.ip.src.build.lwip_lib=-llwip_src -espectro.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -espectro.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" espectro.menu.dbg.Disabled=Disabled espectro.menu.dbg.Disabled.build.debug_port= espectro.menu.dbg.Serial=Serial @@ -6991,13 +6774,6 @@ eduinowifi.menu.ip.hb6f=v2 IPv6 Higher Bandwidth eduinowifi.menu.ip.hb6f.build.lwip_include=lwip2/include eduinowifi.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat eduinowifi.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -eduinowifi.menu.ip.hb1=v1.4 Higher Bandwidth -eduinowifi.menu.ip.hb1.build.lwip_lib=-llwip_gcc -eduinowifi.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -eduinowifi.menu.ip.src=v1.4 Compile from source -eduinowifi.menu.ip.src.build.lwip_lib=-llwip_src -eduinowifi.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -eduinowifi.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" eduinowifi.menu.dbg.Disabled=Disabled eduinowifi.menu.dbg.Disabled.build.debug_port= eduinowifi.menu.dbg.Serial=Serial @@ -7238,13 +7014,6 @@ sonoff.menu.ip.hb6f=v2 IPv6 Higher Bandwidth sonoff.menu.ip.hb6f.build.lwip_include=lwip2/include sonoff.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat sonoff.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -sonoff.menu.ip.hb1=v1.4 Higher Bandwidth -sonoff.menu.ip.hb1.build.lwip_lib=-llwip_gcc -sonoff.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -sonoff.menu.ip.src=v1.4 Compile from source -sonoff.menu.ip.src.build.lwip_lib=-llwip_src -sonoff.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -sonoff.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" sonoff.menu.dbg.Disabled=Disabled sonoff.menu.dbg.Disabled.build.debug_port= sonoff.menu.dbg.Serial=Serial @@ -7476,13 +7245,6 @@ espmxdevkit.menu.ip.hb6f=v2 IPv6 Higher Bandwidth espmxdevkit.menu.ip.hb6f.build.lwip_include=lwip2/include espmxdevkit.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat espmxdevkit.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 -espmxdevkit.menu.ip.hb1=v1.4 Higher Bandwidth -espmxdevkit.menu.ip.hb1.build.lwip_lib=-llwip_gcc -espmxdevkit.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC -espmxdevkit.menu.ip.src=v1.4 Compile from source -espmxdevkit.menu.ip.src.build.lwip_lib=-llwip_src -espmxdevkit.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC -espmxdevkit.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" espmxdevkit.menu.dbg.Disabled=Disabled espmxdevkit.menu.dbg.Disabled.build.debug_port= espmxdevkit.menu.dbg.Serial=Serial diff --git a/cores/esp8266/AddrList.h b/cores/esp8266/AddrList.h index f7adc3d70..33d1f78eb 100644 --- a/cores/esp8266/AddrList.h +++ b/cores/esp8266/AddrList.h @@ -128,7 +128,7 @@ struct netifWrapper const char* ifmac () const { return (const char*)_netif->hwaddr; } int ifnumber () const { return _netif->num; } bool ifUp () const { return !!(_netif->flags & NETIF_FLAG_UP); } - CONST netif* interface () const { return _netif; } + const netif* interface () const { return _netif; } const ip_addr_t* ipFromNetifNum () const { diff --git a/cores/esp8266/Client.h b/cores/esp8266/Client.h index 6cb99a04b..ed0f0f802 100644 --- a/cores/esp8266/Client.h +++ b/cores/esp8266/Client.h @@ -42,11 +42,9 @@ class Client: public Stream { uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); } -#if LWIP_VERSION_MAJOR != 1 const uint8_t* rawIPAddress(const IPAddress& addr) { return addr.raw_address(); } -#endif }; #endif diff --git a/cores/esp8266/Esp-version.cpp b/cores/esp8266/Esp-version.cpp index f92aa2a54..c1ff61eb0 100644 --- a/cores/esp8266/Esp-version.cpp +++ b/cores/esp8266/Esp-version.cpp @@ -21,7 +21,6 @@ #include #include #include -#include // LWIP_VERSION_* #include // LWIP_HASH_STR (lwip2) #include // BEARSSL_GIT short hash @@ -29,13 +28,11 @@ #define STR(x) STRHELPER(x) // stringifier static const char arduino_esp8266_git_ver [] PROGMEM = "/Core:" STR(ARDUINO_ESP8266_GIT_DESC) "="; -#if LWIP_VERSION_MAJOR > 1 #if LWIP_IPV6 static const char lwip_version [] PROGMEM = "/lwIP:IPv6+" LWIP_HASH_STR; #else static const char lwip_version [] PROGMEM = "/lwIP:" LWIP_HASH_STR; #endif -#endif static const char bearssl_version [] PROGMEM = "/BearSSL:" STR(BEARSSL_GIT); String EspClass::getFullVersion() { @@ -45,23 +42,7 @@ String EspClass::getFullVersion() { s += system_get_sdk_version(); s += FPSTR(arduino_esp8266_git_ver); s += String(esp8266::coreVersionNumeric()); -#if LWIP_VERSION_MAJOR == 1 - s += F("/lwIP:"); - s += LWIP_VERSION_MAJOR; - s += '.'; - s += LWIP_VERSION_MINOR; - s += '.'; - s += LWIP_VERSION_REVISION; -#if LWIP_VERSION_IS_DEVELOPMENT - s += F("-dev"); -#endif -#if LWIP_VERSION_IS_RC - s += F("rc"); - s += String(LWIP_VERSION_RC); -#endif -#else // LWIP_VERSION_MAJOR != 1 s += FPSTR(lwip_version); -#endif // LWIP_VERSION_MAJOR != 1 s += FPSTR(bearssl_version); return s; diff --git a/cores/esp8266/IPAddress.cpp b/cores/esp8266/IPAddress.cpp index d121ba6e5..940f5c14d 100644 --- a/cores/esp8266/IPAddress.cpp +++ b/cores/esp8266/IPAddress.cpp @@ -180,7 +180,7 @@ bool IPAddress::isValid(const char* arg) { return IPAddress().fromString(arg); } -CONST IPAddress INADDR_ANY; // generic "0.0.0.0" for IPv4 & IPv6 +const IPAddress INADDR_ANY; // generic "0.0.0.0" for IPv4 & IPv6 const IPAddress INADDR_NONE(255,255,255,255); /**************************************/ diff --git a/cores/esp8266/IPAddress.h b/cores/esp8266/IPAddress.h index cdd4b2499..d2170017e 100644 --- a/cores/esp8266/IPAddress.h +++ b/cores/esp8266/IPAddress.h @@ -26,28 +26,11 @@ #include #include +#include -#if LWIP_VERSION_MAJOR == 1 -// compatibility macros to make lwIP-v1 compiling lwIP-v2 API -#define LWIP_IPV6_NUM_ADDRESSES 0 -#define ip_2_ip4(x) (x) -#define ipv4_addr ip_addr -#define ipv4_addr_t ip_addr_t -#define IP_IS_V4_VAL(x) (1) -#define IP_SET_TYPE_VAL(x,y) do { (void)0; } while (0) -#define IP_ANY_TYPE (&ip_addr_any) -#define IP4_ADDR_ANY IPADDR_ANY -#define IP4_ADDR_ANY4 IP_ADDR_ANY -#define IPADDR4_INIT(x) { x } -#define CONST /* nothing: lwIP-v1 does not use const */ -#define ip4_addr_netcmp ip_addr_netcmp -#define netif_dhcp_data(netif) ((netif)->dhcp) -#else // lwIP-v2+ -#define CONST const #if !LWIP_IPV6 struct ip_addr: ipv4_addr { }; #endif // !LWIP_IPV6 -#endif // lwIP-v2+ // A class to make it easier to handle and pass around IP addresses // IPv6 update: @@ -220,7 +203,7 @@ class IPAddress: public Printable { }; -extern CONST IPAddress INADDR_ANY; +extern const IPAddress INADDR_ANY; extern const IPAddress INADDR_NONE; #endif diff --git a/cores/esp8266/Udp.h b/cores/esp8266/Udp.h index de5127b18..6c8ee4b38 100644 --- a/cores/esp8266/Udp.h +++ b/cores/esp8266/Udp.h @@ -83,14 +83,14 @@ class UDP: public Stream { // Return the port of the host who sent the current incoming packet virtual uint16_t remotePort() =0; protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); } -#if LWIP_VERSION_MAJOR != 1 + const uint8_t* rawIPAddress(const IPAddress& addr) { return addr.raw_address(); } -#endif }; #endif diff --git a/cores/esp8266/sntp-lwip2.cpp b/cores/esp8266/sntp-lwip2.cpp index cc3d8e853..8e8549c33 100644 --- a/cores/esp8266/sntp-lwip2.cpp +++ b/cores/esp8266/sntp-lwip2.cpp @@ -60,44 +60,6 @@ void settimeofday_cb (const TrivialCB& cb) extern "C" { -#if LWIP_VERSION_MAJOR == 1 - -#include - -static const char stod14[] PROGMEM = "settimeofday() can't set time!\n"; -bool sntp_set_timezone(sint8 timezone); -bool sntp_set_timezone_in_seconds(int32_t timezone) -{ - return sntp_set_timezone((sint8)(timezone/(60*60))); //TODO: move this to the same file as sntp_set_timezone() in lwip1.4, and implement correctly over there. -} - -void sntp_set_daylight(int daylight); - -int settimeofday(const struct timeval* tv, const struct timezone* tz) -{ - if (tz) /*before*/ - { - sntp_set_timezone_in_seconds(tz->tz_minuteswest * 60); - // apparently tz->tz_dsttime is a bitfield and should not be further used (cf man) - sntp_set_daylight(0); - } - if (tv) /* after*/ - { - // can't call lwip1.4's static sntp_set_system_time() - os_printf(stod14); - - // reset time subsystem - timeshift64_is_set = false; - - return -1; - } - return 0; -} - -#endif // lwip 1.4 only - -#if LWIP_VERSION_MAJOR == 2 - #include uint32_t sntp_real_timestamp = 0; @@ -128,6 +90,4 @@ int settimeofday(const struct timeval* tv, const struct timezone* tz) return 0; } -#endif // lwip2 only - }; diff --git a/cores/esp8266/time.cpp b/cores/esp8266/time.cpp index ae5a18765..8940fc5d2 100644 --- a/cores/esp8266/time.cpp +++ b/cores/esp8266/time.cpp @@ -73,13 +73,6 @@ int clock_gettime(clockid_t unused, struct timespec *tp) return 0; } -#if LWIP_VERSION_MAJOR == 1 -// hack for espressif time management included in patched lwIP-1.4 -#define sntp_real_timestamp sntp_get_current_timestamp() -#endif - -#if LWIP_VERSION_MAJOR != 1 - // backport Espressif api bool sntp_set_timezone_in_seconds (int32_t timezone_sec) @@ -103,8 +96,6 @@ uint32 sntp_get_current_timestamp() return sntp_real_timestamp; } -#endif - time_t time(time_t * t) { if (t) diff --git a/doc/faq/a05-board-generator.rst b/doc/faq/a05-board-generator.rst index 56adf273a..1e260fa3c 100644 --- a/doc/faq/a05-board-generator.rst +++ b/doc/faq/a05-board-generator.rst @@ -52,8 +52,6 @@ As of today you can: * change led pin ``LED_BUILTIN`` for the two generic boards -* change the default lwIP version (1.4 or 2) - * create an abridged boards.txt file diff --git a/doc/faq/readme.rst b/doc/faq/readme.rst index e4ff8cb79..cbfbdb270 100644 --- a/doc/faq/readme.rst +++ b/doc/faq/readme.rst @@ -129,8 +129,7 @@ This is not needed anymore: PCBs in time-wait state are limited to 5 and removed when that number is exceeded. -Ref. `lwIP-v1.4 `__, -`lwIP-v2 `__ +Ref. ``__ For reference: @@ -139,8 +138,6 @@ same (s-ip,s-port,d-ip,d-port) when the first is already closed but still having duplicate packets lost in internet arriving later during the second. Artificially clearing them is a workaround to help saving precious heap. -The following lines are compatible with both lwIP versions: - .. code:: cpp // no need for #include diff --git a/libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp b/libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp index 557c1117c..1219cfb32 100644 --- a/libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp +++ b/libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp @@ -172,7 +172,7 @@ void ESP8266NetBIOS::end() } } -void ESP8266NetBIOS::_recv(udp_pcb *upcb, pbuf *pb, CONST ip_addr_t *addr, uint16_t port) +void ESP8266NetBIOS::_recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port) { (void)upcb; (void)addr; @@ -180,13 +180,8 @@ void ESP8266NetBIOS::_recv(udp_pcb *upcb, pbuf *pb, CONST ip_addr_t *addr, uint1 while(pb != NULL) { uint8_t * data = (uint8_t*)((pb)->payload); size_t len = pb->len; -#if LWIP_VERSION_MAJOR == 1 - // check UdpContext.h - ip_addr_t* saddr = ¤t_iphdr_src; -#else // check UdpContext.h const ip_addr_t* saddr = &ip_data.current_iphdr_src; -#endif if (len >= sizeof(struct NBNSQUESTION)) { struct NBNSQUESTION * question = (struct NBNSQUESTION *)data; @@ -267,7 +262,7 @@ void ESP8266NetBIOS::_recv(udp_pcb *upcb, pbuf *pb, CONST ip_addr_t *addr, uint1 } } -void ESP8266NetBIOS::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, CONST ip_addr_t *addr, uint16_t port) +void ESP8266NetBIOS::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port) { reinterpret_cast(arg)->_recv(upcb, p, addr, port); } diff --git a/libraries/ESP8266NetBIOS/ESP8266NetBIOS.h b/libraries/ESP8266NetBIOS/ESP8266NetBIOS.h index 1ce8f79cc..10f498a8c 100644 --- a/libraries/ESP8266NetBIOS/ESP8266NetBIOS.h +++ b/libraries/ESP8266NetBIOS/ESP8266NetBIOS.h @@ -3,7 +3,6 @@ #define __ESPNBNS_h__ extern "C" { -#include "lwip/init.h" // LWIP_VERSION_ #include } #include @@ -28,8 +27,8 @@ protected: void _getnbname(char *nbname, char *name, uint8_t maxlen); void _makenbname(char *name, char *nbname, uint8_t outlen); - void _recv(udp_pcb *upcb, pbuf *pb, CONST ip_addr_t *addr, uint16_t port); - static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, CONST ip_addr_t *addr, uint16_t port); + void _recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port); + static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port); public: ESP8266NetBIOS(); diff --git a/libraries/ESP8266WiFi/examples/StaticLease/StaticLease.ino b/libraries/ESP8266WiFi/examples/StaticLease/StaticLease.ino index fa183d0fb..4beaabe2b 100644 --- a/libraries/ESP8266WiFi/examples/StaticLease/StaticLease.ino +++ b/libraries/ESP8266WiFi/examples/StaticLease/StaticLease.ino @@ -1,18 +1,4 @@ -#include - -#if LWIP_VERSION_MAJOR == 1 - -void setup() { - Serial.begin(115200); - Serial.println("wifi_softap_add_dhcps_lease() is not implemented with lwIP-v1"); -} - -void loop() { -} - -#else - /* Create a WiFi access point and provide static lease */ #include @@ -104,5 +90,3 @@ void setup() { void loop() { server.handleClient(); } - -#endif // lwIP-v2 diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp index 41d771fb6..e026ea760 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp @@ -41,12 +41,7 @@ extern "C" { #include "lwip/err.h" #include "lwip/dns.h" #include "lwip/dhcp.h" -#include "lwip/init.h" // LWIP_VERSION_ -#if LWIP_VERSION_MAJOR == 1 -#include "lwip/sntp.h" -#else #include "lwip/apps/sntp.h" -#endif } #include "WiFiClient.h" @@ -588,7 +583,7 @@ bool ESP8266WiFiGenericClass::isSleepLevelMax () { // ------------------------------------------------ Generic Network function --------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------- -void wifi_dns_found_callback(const char *name, CONST ip_addr_t *ipaddr, void *callback_arg); +void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg); static bool _dns_lookup_pending = false; @@ -701,7 +696,7 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul * @param ipaddr * @param callback_arg */ -void wifi_dns_found_callback(const char *name, CONST ip_addr_t *ipaddr, void *callback_arg) +void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg) { (void) name; if (!_dns_lookup_pending) { @@ -770,11 +765,7 @@ bool ESP8266WiFiGenericClass::shutdown (uint32 sleepUs, WiFiState* state) uint8_t i = 0; for (auto& ntp: state->state.ntp) { -#if LWIP_VERSION_MAJOR == 1 - ntp = sntp_getserver(i++); -#else ntp = *sntp_getserver(i++); -#endif } i = 0; for (auto& dns: state->state.dns) @@ -814,7 +805,7 @@ bool ESP8266WiFiGenericClass::resumeFromShutdown (WiFiState* state) DEBUG_WIFI("core: resume: static address '%s'\n", local.toString().c_str()); WiFi.config(state->state.ip.ip, state->state.ip.gw, state->state.ip.netmask, state->state.dns[0], state->state.dns[1]); uint8_t i = 0; - for (CONST auto& ntp: state->state.ntp) + for (const auto& ntp: state->state.ntp) { IPAddress ip(ntp); if (ip.isSet()) diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.cpp index 1ba3f862b..089b8289d 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.cpp @@ -19,14 +19,7 @@ extern "C" { -#include "lwip/init.h" // LWIP_VERSION_* -#if LWIP_VERSION_MAJOR == 1 -#include "netif/wlan_lwip_if.h" // eagle_lwip_getif() -#include "netif/etharp.h" // gratuitous arp -#include "user_interface.h" -#else #include "lwip/etharp.h" // gratuitous arp -#endif } // extern "C" #include @@ -44,14 +37,8 @@ void ESP8266WiFiGratuitous::stationKeepAliveNow () if ( (interface->flags & NETIF_FLAG_LINK_UP) && (interface->flags & NETIF_FLAG_UP) -#if LWIP_VERSION_MAJOR == 1 - && interface == eagle_lwip_getif(STATION_IF) /* lwip1 does not set if->num properly */ - && (!ip_addr_isany(&interface->ip_addr)) -#else && interface->num == STATION_IF - && (!ip4_addr_isany_val(*netif_ip4_addr(interface))) -#endif - ) + && (!ip4_addr_isany_val(*netif_ip4_addr(interface)))) { etharp_gratuitous(interface); break; diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp index 26fb4b9d3..5082dfd88 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp @@ -39,10 +39,6 @@ extern "C" { #include "lwip/err.h" #include "lwip/dns.h" #include "lwip/dhcp.h" -#include "lwip/init.h" // LWIP_VERSION_ -#if LWIP_IPV6 -#include "lwip/netif.h" // struct netif -#endif } #include "debug.h" @@ -249,7 +245,6 @@ wl_status_t ESP8266WiFiSTAClass::begin() { * @param dns2 Static DNS server 2 */ -#if LWIP_VERSION_MAJOR != 1 /* About the following call in the end of ESP8266WiFiSTAClass::config(): netif_set_addr(eagle_lwip_getif(STATION_IF), &info.ip, &info.netmask, &info.gw); @@ -267,7 +262,6 @@ wl_status_t ESP8266WiFiSTAClass::begin() { #undef netif_set_addr // need to call lwIP-v1.4 netif_set_addr() extern "C" struct netif* eagle_lwip_getif (int netif_index); extern "C" void netif_set_addr (struct netif* netif, ip4_addr_t* ip, ip4_addr_t* netmask, ip4_addr_t* gw); -#endif bool ESP8266WiFiSTAClass::config(IPAddress local_ip, IPAddress arg1, IPAddress arg2, IPAddress arg3, IPAddress dns2) { @@ -310,7 +304,7 @@ bool ESP8266WiFiSTAClass::config(IPAddress local_ip, IPAddress arg1, IPAddress a return false; } -#if LWIP_VERSION_MAJOR != 1 && !CORE_MOCK +#if !CORE_MOCK // get current->previous IP address // (check below) struct ip_info previp; @@ -339,7 +333,7 @@ bool ESP8266WiFiSTAClass::config(IPAddress local_ip, IPAddress arg1, IPAddress a dns_setserver(1, dns2); } -#if LWIP_VERSION_MAJOR != 1 && !CORE_MOCK +#if !CORE_MOCK // trigger address change by calling lwIP-v1.4 api // (see explanation above) // only when ip is already set by other mean (generally dhcp) @@ -525,12 +519,7 @@ IPAddress ESP8266WiFiSTAClass::gatewayIP() { * @return IPAddress DNS Server IP */ IPAddress ESP8266WiFiSTAClass::dnsIP(uint8_t dns_no) { -#if LWIP_VERSION_MAJOR == 1 - ip_addr_t dns_ip = dns_getserver(dns_no); - return IPAddress(dns_ip.addr); -#else return IPAddress(dns_getserver(dns_no)); -#endif } @@ -605,11 +594,7 @@ bool ESP8266WiFiSTAClass::hostname(const char* aHostname) { for (netif* intf = netif_list; intf; intf = intf->next) { // unconditionally update all known interfaces -#if LWIP_VERSION_MAJOR == 1 - intf->hostname = (char*)wifi_station_get_hostname(); -#else intf->hostname = wifi_station_get_hostname(); -#endif if (netif_dhcp_data(intf) != nullptr) { // renew already started DHCP leases diff --git a/libraries/ESP8266WiFi/src/WiFiClient.cpp b/libraries/ESP8266WiFi/src/WiFiClient.cpp index abd277229..1663a29ec 100644 --- a/libraries/ESP8266WiFi/src/WiFiClient.cpp +++ b/libraries/ESP8266WiFi/src/WiFiClient.cpp @@ -145,17 +145,6 @@ int WiFiClient::connect(IPAddress ip, uint16_t port) _client = nullptr; } -#if LWIP_VERSION_MAJOR == 1 - // if the default interface is down, tcp_connect exits early without - // ever calling tcp_err - // http://lists.gnu.org/archive/html/lwip-devel/2010-05/msg00001.html - netif* interface = ip_route(ip); - if (!interface) { - DEBUGV("no route to host\r\n"); - return 0; - } -#endif - tcp_pcb* pcb = tcp_new(); if (!pcb) return 0; diff --git a/libraries/ESP8266WiFi/src/WiFiServer.cpp b/libraries/ESP8266WiFi/src/WiFiServer.cpp index 0b0de5d42..2ee09f85f 100644 --- a/libraries/ESP8266WiFi/src/WiFiServer.cpp +++ b/libraries/ESP8266WiFi/src/WiFiServer.cpp @@ -35,7 +35,6 @@ extern "C" { #include "lwip/opt.h" #include "lwip/tcp.h" #include "lwip/inet.h" -#include "lwip/init.h" // LWIP_VERSION_ #include #ifndef MAX_PENDING_CLIENTS_PER_PORT @@ -85,11 +84,7 @@ void WiFiServer::begin(uint16_t port, uint8_t backlog) { return; } -#if LWIP_VERSION_MAJOR == 1 - tcp_pcb* listen_pcb = tcp_listen(pcb); -#else tcp_pcb* listen_pcb = tcp_listen_with_backlog(pcb, backlog); -#endif if (!listen_pcb) { tcp_close(pcb); @@ -124,12 +119,12 @@ WiFiClient WiFiServer::available(byte* status) { (void) status; if (_unclaimed) { WiFiClient result(_unclaimed); -#if LWIP_VERSION_MAJOR != 1 + // pcb can be null when peer has already closed the connection if (_unclaimed->getPCB()) // give permission to lwIP to accept one more peer tcp_backlog_accepted(_unclaimed->getPCB()); -#endif + _unclaimed = _unclaimed->next(); result.setNoDelay(getNoDelay()); DEBUGV("WS:av status=%d WCav=%d\r\n", result.status(), result.available()); @@ -193,12 +188,6 @@ long WiFiServer::_accept(tcp_pcb* apcb, long err) { // user calls ::available() ClientContext* client = new ClientContext(apcb, &WiFiServer::_s_discard, this); -#if LWIP_VERSION_MAJOR == 1 - - tcp_accepted(_listen_pcb); - -#else - // backlog doc: // http://lwip.100.n7.nabble.com/Problem-re-opening-listening-pbc-tt32484.html#a32494 // https://www.nongnu.org/lwip/2_1_x/group__tcp__raw.html#gaeff14f321d1eecd0431611f382fcd338 @@ -206,8 +195,6 @@ long WiFiServer::_accept(tcp_pcb* apcb, long err) { // increase lwIP's backlog tcp_backlog_delayed(apcb); -#endif - _unclaimed = slist_append_tail(_unclaimed, client); return ERR_OK; diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h index a81384b2a..8053748cd 100644 --- a/libraries/ESP8266WiFi/src/include/UdpContext.h +++ b/libraries/ESP8266WiFi/src/include/UdpContext.h @@ -26,7 +26,6 @@ class UdpContext; extern "C" { void esp_yield(); void esp_schedule(); -#include "lwip/init.h" // LWIP_VERSION_ #include } @@ -92,24 +91,6 @@ public: } } -#if LWIP_VERSION_MAJOR == 1 - - bool connect(IPAddress addr, uint16_t port) - { - _pcb->remote_ip = addr; - _pcb->remote_port = port; - return true; - } - - bool listen(IPAddress addr, uint16_t port) - { - udp_recv(_pcb, &_s_recv, (void *) this); - err_t err = udp_bind(_pcb, addr, port); - return err == ERR_OK; - } - -#else // lwIP-v2 - bool connect(const IPAddress& addr, uint16_t port) { _pcb->remote_ip = addr; @@ -130,8 +111,6 @@ public: return err == ERR_OK; } -#endif // lwIP-v2 - void disconnect() { udp_disconnect(_pcb); @@ -166,11 +145,7 @@ public: void setMulticastInterface(const IPAddress& addr) { -#if LWIP_VERSION_MAJOR == 1 - udp_set_multicast_netif_addr(_pcb, (ip_addr_t)addr); -#else udp_set_multicast_netif_addr(_pcb, ip_2_ip4((const ip_addr_t*)addr)); -#endif } #endif // !LWIP_IPV6 @@ -180,11 +155,7 @@ public: */ void setMulticastInterface(netif* p_pNetIf) { -#if LWIP_VERSION_MAJOR == 1 - udp_set_multicast_netif_addr(_pcb, (p_pNetIf ? p_pNetIf->ip_addr : ip_addr_any)); -#else udp_set_multicast_netif_index(_pcb, (p_pNetIf ? netif_get_index(p_pNetIf) : NETIF_NO_INDEX)); -#endif } /* @@ -262,7 +233,7 @@ public: return _currentAddr.input_netif; } - CONST IPAddress& getRemoteAddress() CONST + const IPAddress& getRemoteAddress() const { return _currentAddr.srcaddr; } @@ -419,7 +390,7 @@ public: return size; } - bool send(CONST ip_addr_t* addr = 0, uint16_t port = 0) + bool send(const ip_addr_t* addr = 0, uint16_t port = 0) { size_t data_size = _tx_buf_offset; pbuf* tx_copy = pbuf_alloc(PBUF_TRANSPORT, data_size, PBUF_RAM); @@ -537,14 +508,6 @@ private: } } -#if LWIP_VERSION_MAJOR == 1 - #define TEMPDSTADDR (¤t_iphdr_dest) - #define TEMPINPUTNETIF (current_netif) -#else - #define TEMPDSTADDR (ip_current_dest_addr()) - #define TEMPINPUTNETIF (ip_current_input_netif()) -#endif - // chain this helper pbuf first if (_rx_buf) { @@ -570,7 +533,7 @@ private: return; } // construct in place - new(PBUF_ALIGNER(pb_helper->payload)) AddrHelper(srcaddr, TEMPDSTADDR, srcport, TEMPINPUTNETIF); + new(PBUF_ALIGNER(pb_helper->payload)) AddrHelper(srcaddr, ip_current_dest_addr(), srcport, ip_current_input_netif()); pb_helper->flags = PBUF_HELPER_FLAG; // mark helper pbuf // chain it pbuf_cat(_rx_buf, pb_helper); @@ -582,9 +545,9 @@ private: else { _currentAddr.srcaddr = srcaddr; - _currentAddr.dstaddr = TEMPDSTADDR; + _currentAddr.dstaddr = ip_current_dest_addr(); _currentAddr.srcport = srcport; - _currentAddr.input_netif = TEMPINPUTNETIF; + _currentAddr.input_netif = ip_current_input_netif(); DEBUGV(":urn %d\r\n", pb->tot_len); _first_buf_taken = false; @@ -597,102 +560,15 @@ private: _on_rx(); } - #undef TEMPDSTADDR - #undef TEMPINPUTNETIF - } static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, - CONST ip_addr_t *srcaddr, u16_t srcport) + const ip_addr_t *srcaddr, u16_t srcport) { reinterpret_cast(arg)->_recv(upcb, p, srcaddr, srcport); } -#if LWIP_VERSION_MAJOR == 1 - /* - * Code in this conditional block is copied/backported verbatim from - * LwIP 2.1.2 to provide pbuf_get_contiguous. - */ - - 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 *pbuf_it = in; - - /* get the correct pbuf */ - while ((pbuf_it != NULL) && (pbuf_it->len <= offset_left)) { - offset_left = (u16_t)(offset_left - pbuf_it->len); - pbuf_it = pbuf_it->next; - } - if (out_offset != NULL) { - *out_offset = offset_left; - } - return pbuf_it; - } - - u16_t - pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) - { - const struct pbuf *p; - u16_t left = 0; - u16_t buf_copy_len; - u16_t copied_total = 0; - - LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); - LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (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) { - if ((offset != 0) && (offset >= p->len)) { - /* don't copy from this buffer -> on to the next */ - offset = (u16_t)(offset - p->len); - } else { - /* copy from this buffer. maybe only partially. */ - buf_copy_len = (u16_t)(p->len - offset); - 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 = (u16_t)(copied_total + buf_copy_len); - left = (u16_t)(left + buf_copy_len); - len = (u16_t)(len - buf_copy_len); - offset = 0; - } - } - return copied_total; - } - - void * - pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset) - { - const struct pbuf *q; - u16_t out_offset; - - LWIP_ERROR("pbuf_get_contiguous: invalid buf", (p != NULL), return NULL;); - LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (buffer != NULL), return NULL;); - LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (bufsize >= len), return NULL;); - - q = pbuf_skip_const(p, offset, &out_offset); - if (q != NULL) { - if (q->len >= (out_offset + len)) { - /* all data in this pbuf, return zero-copy */ - return (u8_t *)q->payload + out_offset; - } - /* need to copy */ - if (pbuf_copy_partial(q, buffer, len, out_offset) != len) { - /* copying failed: pbuf is too short */ - return NULL; - } - return buffer; - } - /* pbuf is too short (offset does not fit in) */ - return NULL; - } -#endif - private: udp_pcb* _pcb; pbuf* _rx_buf; diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.h b/libraries/ESP8266mDNS/src/LEAmDNS.h index fe02560ae..7dfd333f1 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS.h @@ -1203,7 +1203,7 @@ protected: MDNSDynamicServiceTxtCallbackFunc m_fnServiceTxtCallback; bool m_bPassivModeEnabled; stcProbeInformation m_HostProbeInformation; - CONST netif* m_netif; // network interface to run on + const netif* m_netif; // network interface to run on /** CONTROL **/ /* MAINTENANCE */ diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h b/libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h index a3bcc4b37..3686440f1 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h @@ -25,20 +25,6 @@ #ifndef MDNS_LWIPDEFS_H #define MDNS_LWIPDEFS_H -#include -#if LWIP_VERSION_MAJOR == 1 - -#include // DNS_RRTYPE_xxx - -// cherry pick from lwip1 dns.c/mdns.c source files: -#define DNS_MQUERY_PORT 5353 -#define DNS_MQUERY_IPV4_GROUP_INIT IPAddress(224,0,0,251) /* resolver1.opendns.com */ -#define DNS_RRCLASS_ANY 255 /* any class */ - -#else // lwIP > 1 - #include // DNS_RRTYPE_xxx, DNS_MQUERY_PORT -#endif - #endif // MDNS_LWIPDEFS_H diff --git a/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino b/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino index 3a16efb61..d66833ae2 100644 --- a/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino +++ b/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino @@ -140,8 +140,6 @@ void showTime() { Serial.print("ctime: "); Serial.print(ctime(&now)); -#if LWIP_VERSION_MAJOR > 1 - // LwIP v2 is able to list more details about the currently configured SNTP servers for (int i = 0; i < SNTP_MAX_SERVERS; i++) { IPAddress sntp = *sntp_getserver(i); @@ -158,7 +156,6 @@ void showTime() { sntp_getreachability(i)); } } -#endif Serial.println(); } diff --git a/tests/debug.sh b/tests/debug.sh index 9f4aea603..bbca35ff5 100755 --- a/tests/debug.sh +++ b/tests/debug.sh @@ -16,4 +16,3 @@ install_arduino debug build_sketches_with_arduino "$mod" "$rem" lm2f rm -rf "$cache_dir" - diff --git a/tests/build1.sh b/tests/debug6.sh similarity index 80% rename from tests/build1.sh rename to tests/debug6.sh index df50b4c38..bf2d4f519 100755 --- a/tests/build1.sh +++ b/tests/debug6.sh @@ -15,8 +15,8 @@ elif [ "$BUILD_PARITY" = "odd" ]; then rem=1 fi -install_arduino nodebug -build_sketches_with_arduino "$mod" "$rem" hb1 +install_arduino debug +build_sketches_with_arduino "$mod" "$rem" lm6f rm -rf "$cache_dir" diff --git a/tests/run_CI_locally.sh b/tests/run_CI_locally.sh index c079c2a63..6d0a97093 100755 --- a/tests/run_CI_locally.sh +++ b/tests/run_CI_locally.sh @@ -54,7 +54,6 @@ while true; do Which build? 1. main 2. main + IPv6 -3. main with lwIP-v1.4 4. debug even 5. debug odd 6. platformio @@ -69,7 +68,6 @@ EOF case "$ans" in 1) BUILD_TYPE=build;; 2) BUILD_TYPE=build6;; - 3) BUILD_TYPE=build1;; 4) BUILD_TYPE=debug_even;; 5) BUILD_TYPE=debug_odd;; 6) BUILD_TYPE=platformio;; @@ -106,13 +104,6 @@ elif [ "$BUILD_TYPE" = "build6_even" ]; then elif [ "$BUILD_TYPE" = "build6_odd" ]; then BUILD_PARITY=odd tests/build6.sh -elif [ "$BUILD_TYPE" = "build1" ]; then - tests/build1.sh -elif [ "$BUILD_TYPE" = "build1_even" ]; then - BUILD_PARITY=even tests/build1.sh -elif [ "$BUILD_TYPE" = "build1_odd" ]; then - BUILD_PARITY=odd tests/build1.sh - elif [ "$BUILD_TYPE" = "platformio" ]; then tests/platformio.sh elif [ "$BUILD_TYPE" = "platformio_even" ]; then diff --git a/tools/boards.txt.py b/tools/boards.txt.py index 69793489a..789f75714 100755 --- a/tools/boards.txt.py +++ b/tools/boards.txt.py @@ -30,7 +30,7 @@ # crystalfreq/flashfreq_menu: menus for crystal/flash frequency selection # flashmode_menu: menus for flashmode selection (dio/dout/qio/qout) # 512K/1M/2M/4M/8M/16M: menus for flash & FS size -# lwip/lwip2 menus for available lwip versions +# lwip menus for available lwip versions from __future__ import print_function import os @@ -1115,7 +1115,7 @@ macros = { ####################### lwip - 'lwip2': collections.OrderedDict([ + 'lwip': collections.OrderedDict([ ( '.menu.ip.lm2f', 'v2 Lower Memory' ), ( '.menu.ip.lm2f.build.lwip_include', 'lwip2/include' ), ( '.menu.ip.lm2f.build.lwip_lib', '-llwip2-536-feat' ), @@ -1142,19 +1142,6 @@ macros = { ( '.menu.ip.hb6f.build.lwip_flags', '-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1' ), ]), - 'lwip': collections.OrderedDict([ - ( '.menu.ip.hb1', 'v1.4 Higher Bandwidth' ), - ( '.menu.ip.hb1.build.lwip_lib', '-llwip_gcc' ), - ( '.menu.ip.hb1.build.lwip_flags', '-DLWIP_OPEN_SRC' ), - #( '.menu.ip.Espressif', 'v1.4 Espressif (xcc)' ), - #( '.menu.ip.Espressif.build.lwip_lib', '-llwip' ), - #( '.menu.ip.Espressif.build.lwip_flags', '-DLWIP_MAYBE_XCC' ), - ( '.menu.ip.src', 'v1.4 Compile from source' ), - ( '.menu.ip.src.build.lwip_lib', '-llwip_src' ), - ( '.menu.ip.src.build.lwip_flags', '-DLWIP_OPEN_SRC' ), - ( '.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern', 'make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-"' ), - ]), - ####################### serial 's9': collections.OrderedDict([ @@ -1598,11 +1585,7 @@ def all_boards (): macrolist = [ 'defaults', 'cpufreq_menu', 'vtable_menu', 'exception_menu', 'stacksmash_menu', 'ssl_cipher_menu' ] if 'macro' in board: macrolist += board['macro'] - if lwip == 2: - macrolist += [ 'lwip2', 'lwip' ] - else: - macrolist += [ 'lwip', 'lwip2' ] - macrolist += [ 'debug_menu', 'flash_erase_menu' ] + macrolist += [ 'lwip', 'debug_menu', 'flash_erase_menu' ] for cs in customspeeds: print(id + cs) @@ -1732,7 +1715,6 @@ def usage (name,ret): print("usage: %s [options]" % name) print("") print(" -h, --help") - print(" --lwip - preferred default lwIP version (default %d)" % lwip) print(" --led - preferred default builtin led for generic boards (default %d)" % led_default) print(" --board - board to modify:") print(" --filter - create a short boards.txt based on the boards listed in ") @@ -1781,7 +1763,6 @@ def usage (name,ret): ################################################################ # entry point -lwip = 2 default_speed = '115' led_default = 2 led_max = 16 @@ -1809,7 +1790,7 @@ lddir = "tools/sdk/ld/" try: opts, args = getopt.getopt(sys.argv[1:], "h", - [ "help", "lwip=", "led=", "speed=", "board=", "customspeed=", "nofloat", + [ "help", "led=", "speed=", "board=", "customspeed=", "nofloat", "noextra4kheap", "allowWPS", "boardslocalgen", "filter=", "xfilter=", "boardnames", "ld", "ldgen", "boards", "boardsgen", "package", "packagegen", "doc", "docgen", @@ -1829,9 +1810,6 @@ for o, a in opts: elif o in ("--boardnames"): boardnames() - elif o in ("--lwip"): - lwip = a - elif o in ("--led"): led_default = int(a) diff --git a/tools/platformio-build.py b/tools/platformio-build.py index 30b842728..1af8ff9a3 100644 --- a/tools/platformio-build.py +++ b/tools/platformio-build.py @@ -199,12 +199,7 @@ else: #(default) if "PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703" in flatten_c # # lwIP # -if "PIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH" in flatten_cppdefines: - env.Append( - CPPPATH=[join(FRAMEWORK_DIR, "tools", "sdk", "lwip", "include")], - LIBS=["lwip_gcc"] - ) -elif "PIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY" in flatten_cppdefines: +if "PIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY" in flatten_cppdefines: env.Append( CPPDEFINES=[("TCP_MSS", 536), ("LWIP_FEATURES", 1), ("LWIP_IPV6", 1)], CPPPATH=[join(FRAMEWORK_DIR, "tools", "sdk", "lwip2", "include")], diff --git a/tools/sdk/include/ipv4_addr.h b/tools/sdk/include/ipv4_addr.h index 7a8ed35aa..8d8747866 100644 --- a/tools/sdk/include/ipv4_addr.h +++ b/tools/sdk/include/ipv4_addr.h @@ -34,16 +34,9 @@ // hence ipv4_addr/t is IPv4 version/copy of IPv4 ip_addr/_t // when IPv6 is enabled so we can deal with IPv4 use from firmware API. -// official lwIP's definitions (1.4 or 2) +// official lwIP's definitions #include "lwip/ip_addr.h" - -/////////////////////////////////////////////// -#if LWIP_VERSION_MAJOR == 1 - -#define ipv4_addr ip_addr - -/////////////////////////////////////////////// -#else // lwIP-v2 +#include #define ipv4_addr ip4_addr #define ipv4_addr_t ip4_addr_t @@ -55,7 +48,4 @@ struct ip_info { struct ipv4_addr gw; }; -/////////////////////////////////////////////// -#endif // lwIP-v2 - #endif // __IPV4_ADDR_H__ diff --git a/tools/sdk/include/sntp.h b/tools/sdk/include/sntp.h index 294711057..bb85e678b 100644 --- a/tools/sdk/include/sntp.h +++ b/tools/sdk/include/sntp.h @@ -5,11 +5,7 @@ #include "lwip/init.h" #include "lwip/ip_addr.h" -#if LWIP_VERSION_MAJOR == 1 -#include "lwip/sntp.h" -#else #include "lwip/apps/sntp.h" -#endif #ifdef __cplusplus extern "C" { diff --git a/tools/sdk/lib/liblwip_gcc.a b/tools/sdk/lib/liblwip_gcc.a deleted file mode 100644 index 9ec42e0b78550a2608112d58474aa5fea8e2ed05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1207642 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

CCYZWQ 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

5FxI9>THK-m{P(4b5;Aq0F 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

b5^prp#~x>E9TfRP_$xWF*SD$_n~rQwN& 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%0AmsMZZMJ8%*{*N1{j)aPXJeZ~3!n8$NB`t$ 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�)b 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 - * - */ -#ifndef __ARCH_CC_H__ -#define __ARCH_CC_H__ - -//#include -#include "c_types.h" -#include "ets_sys.h" -#include "osapi.h" -#define EFAULT 14 -#include -#include <../../../cores/esp8266/core_esp8266_features.h> - -//#define LWIP_PROVIDE_ERRNO - -#if (1) -#define BYTE_ORDER LITTLE_ENDIAN -#else -#define BYTE_ORDER BIG_ENDIAN -#endif - - -typedef unsigned char u8_t; -typedef signed char s8_t; -typedef unsigned short u16_t; -typedef signed short s16_t; -typedef unsigned long u32_t; -typedef signed long s32_t; -typedef unsigned long mem_ptr_t; - -#define S16_F "d" -#define U16_F "d" -#define X16_F "x" - -#define S32_F "d" -#define U32_F "d" -#define X32_F "x" - -#define LWIP_ERR_T s32_t - -//#define PACK_STRUCT_FIELD(x) x __attribute__((packed)) -#define PACK_STRUCT_FIELD(x) x -#define PACK_STRUCT_STRUCT __attribute__((packed)) -#define PACK_STRUCT_BEGIN -#define PACK_STRUCT_END - -//#define LWIP_DEBUG - -#ifdef LWIP_DEBUG -#define LWIP_PLATFORM_DIAG(x) os_printf x -#define LWIP_PLATFORM_ASSERT(x) ETS_ASSERT(x) -#else -#define LWIP_PLATFORM_DIAG(x) -#define LWIP_PLATFORM_ASSERT(x) -#endif - -typedef uint32_t sys_prot_t; -#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev -#define SYS_ARCH_PROTECT(lev) lev = xt_rsil(15) -#define SYS_ARCH_UNPROTECT(lev) xt_wsr_ps(lev) - -#define LWIP_PLATFORM_BYTESWAP 1 -#define LWIP_PLATFORM_HTONS(_n) ((u16_t)((((_n) & 0xff) << 8) | (((_n) >> 8) & 0xff))) -#define LWIP_PLATFORM_HTONL(_n) ((u32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) )) - -#if LWIP_RAW -extern u8_t memp_memory_RAW_PCB_base[]; -#endif /* LWIP_RAW */ - -#if LWIP_UDP -extern u8_t memp_memory_UDP_PCB_base[]; -#endif /* LWIP_UDP */ - -#if LWIP_TCP -extern u8_t memp_memory_TCP_PCB_base[]; -extern u8_t memp_memory_TCP_PCB_LISTEN_base[]; -extern u8_t memp_memory_TCP_SEG_base[] SHMEM_ATTR; -#endif /* LWIP_TCP */ - -#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */ -extern u8_t memp_memory_SYS_TIMEOUT_base[]; -#endif /* LWIP_TIMERS */ - -extern u8_t memp_memory_PBUF_base[]; -extern u8_t memp_memory_PBUF_POOL_base[]; - - - -#endif /* __ARCH_CC_H__ */ diff --git a/tools/sdk/lwip/include/arch/perf.h b/tools/sdk/lwip/include/arch/perf.h deleted file mode 100644 index 089facac1..000000000 --- a/tools/sdk/lwip/include/arch/perf.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2001, 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. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 - * - */ -#ifndef __PERF_H__ -#define __PERF_H__ - -#define PERF_START /* null definition */ -#define PERF_STOP(x) /* null definition */ - -#endif /* __PERF_H__ */ diff --git a/tools/sdk/lwip/include/arch/sys_arch.h b/tools/sdk/lwip/include/arch/sys_arch.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/tools/sdk/lwip/include/lwip/api.h b/tools/sdk/lwip/include/lwip/api.h deleted file mode 100644 index 91b9e5d24..000000000 --- a/tools/sdk/lwip/include/lwip/api.h +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_API_H__ -#define __LWIP_API_H__ - -#include "lwip/opt.h" - -#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ - -#include /* for size_t */ - -#include "lwip/netbuf.h" -#include "lwip/sys.h" -#include "lwip/ip_addr.h" -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Throughout this file, IP addresses and port numbers are expected to be in - * the same byte order as in the corresponding pcb. - */ - -/* Flags for netconn_write (u8_t) */ -#define NETCONN_NOFLAG 0x00 -#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ -#define NETCONN_COPY 0x01 -#define NETCONN_MORE 0x02 -#define NETCONN_DONTBLOCK 0x04 - -/* Flags for struct netconn.flags (u8_t) */ -/** TCP: when data passed to netconn_write doesn't fit into the send buffer, - this temporarily stores whether to wake up the original application task - if data couldn't be sent in the first try. */ -#define NETCONN_FLAG_WRITE_DELAYED 0x01 -/** Should this netconn avoid blocking? */ -#define NETCONN_FLAG_NON_BLOCKING 0x02 -/** Was the last connect action a non-blocking one? */ -#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04 -/** If this is set, a TCP netconn must call netconn_recved() to update - the TCP receive window (done automatically if not set). */ -#define NETCONN_FLAG_NO_AUTO_RECVED 0x08 -/** If a nonblocking write has been rejected before, poll_tcp needs to - check if the netconn is writable again */ -#define NETCONN_FLAG_CHECK_WRITESPACE 0x10 - - -/* Helpers to process several netconn_types by the same code */ -#define NETCONNTYPE_GROUP(t) (t&0xF0) -#define NETCONNTYPE_DATAGRAM(t) (t&0xE0) - -/** Protocol family and type of the netconn */ -enum netconn_type { - NETCONN_INVALID = 0, - /* NETCONN_TCP Group */ - NETCONN_TCP = 0x10, - /* NETCONN_UDP Group */ - NETCONN_UDP = 0x20, - NETCONN_UDPLITE = 0x21, - NETCONN_UDPNOCHKSUM= 0x22, - /* NETCONN_RAW Group */ - NETCONN_RAW = 0x40 -}; - -/** Current state of the netconn. Non-TCP netconns are always - * in state NETCONN_NONE! */ -enum netconn_state { - NETCONN_NONE, - NETCONN_WRITE, - NETCONN_LISTEN, - NETCONN_CONNECT, - NETCONN_CLOSE -}; - -/** Use to inform the callback function about changes */ -enum netconn_evt { - NETCONN_EVT_RCVPLUS, - NETCONN_EVT_RCVMINUS, - NETCONN_EVT_SENDPLUS, - NETCONN_EVT_SENDMINUS, - NETCONN_EVT_ERROR -}; - -#if LWIP_IGMP -/** Used for netconn_join_leave_group() */ -enum netconn_igmp { - NETCONN_JOIN, - NETCONN_LEAVE -}; -#endif /* LWIP_IGMP */ - -/* forward-declare some structs to avoid to include their headers */ -struct ip_pcb; -struct tcp_pcb; -struct udp_pcb; -struct raw_pcb; -struct netconn; -struct api_msg_msg; - -/** A callback prototype to inform about events for a netconn */ -typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len); - -/** A netconn descriptor */ -struct netconn { - /** type of the netconn (TCP, UDP or RAW) */ - enum netconn_type type; - /** current state of the netconn */ - enum netconn_state state; - /** the lwIP internal protocol control block */ - union { - struct ip_pcb *ip; - struct tcp_pcb *tcp; - struct udp_pcb *udp; - struct raw_pcb *raw; - } pcb; - /** the last error this netconn had */ - err_t last_err; - /** sem that is used to synchroneously execute functions in the core context */ - sys_sem_t op_completed; - /** mbox where received packets are stored until they are fetched - by the netconn application thread (can grow quite big) */ - sys_mbox_t recvmbox; -#if LWIP_TCP - /** mbox where new connections are stored until processed - by the application thread */ - sys_mbox_t acceptmbox; -#endif /* LWIP_TCP */ - /** only used for socket layer */ -#if LWIP_SOCKET - int socket; -#endif /* LWIP_SOCKET */ -#if LWIP_SO_RCVTIMEO - /** timeout to wait for new data to be received - (or connections to arrive for listening netconns) */ - int recv_timeout; -#endif /* LWIP_SO_RCVTIMEO */ -#if LWIP_SO_RCVBUF - /** maximum amount of bytes queued in recvmbox - not used for TCP: adjust TCP_WND instead! */ - int recv_bufsize; - /** number of bytes currently in recvmbox to be received, - tested against recv_bufsize to limit bytes on recvmbox - for UDP and RAW, used for FIONREAD */ - s16_t recv_avail; -#endif /* LWIP_SO_RCVBUF */ - /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ - u8_t flags; -#if LWIP_TCP - /** TCP: when data passed to netconn_write doesn't fit into the send buffer, - this temporarily stores how much is already sent. */ - size_t write_offset; - /** TCP: when data passed to netconn_write doesn't fit into the send buffer, - this temporarily stores the message. - Also used during connect and close. */ - struct api_msg_msg *current_msg; -#endif /* LWIP_TCP */ - /** A callback function that is informed about events for this netconn */ - netconn_callback callback; -}; - -/** Register an Network connection event */ -#define API_EVENT(c,e,l) if (c->callback) { \ - (*c->callback)(c, e, l); \ - } - -/** Set conn->last_err to err but don't overwrite fatal errors */ -#define NETCONN_SET_SAFE_ERR(conn, err) do { \ - SYS_ARCH_DECL_PROTECT(lev); \ - SYS_ARCH_PROTECT(lev); \ - if (!ERR_IS_FATAL((conn)->last_err)) { \ - (conn)->last_err = err; \ - } \ - SYS_ARCH_UNPROTECT(lev); \ -} while(0); - -/* Network connection functions: */ -#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL) -#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c) -struct -netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, - netconn_callback callback); -err_t netconn_delete(struct netconn *conn); -/** Get the type of a netconn (as enum netconn_type). */ -#define netconn_type(conn) (conn->type) - -err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, - u16_t *port, u8_t local); -#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) -#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) - -err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port); -err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port); -err_t netconn_disconnect (struct netconn *conn); -err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); -#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG) -err_t netconn_accept(struct netconn *conn, struct netconn **new_conn); -err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf); -err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); -void netconn_recved(struct netconn *conn, u32_t length); -err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, - ip_addr_t *addr, u16_t port); -err_t netconn_send(struct netconn *conn, struct netbuf *buf); -err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size, - u8_t apiflags); -err_t netconn_close(struct netconn *conn); -err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx); - -#if LWIP_IGMP -err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr, - ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); -#endif /* LWIP_IGMP */ -#if LWIP_DNS -err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); -#endif /* LWIP_DNS */ - -#define netconn_err(conn) ((conn)->last_err) -#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) - -/** Set the blocking status of netconn calls (@todo: write/send is missing) */ -#define netconn_set_nonblocking(conn, val) do { if(val) { \ - (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \ -} else { \ - (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0) -/** Get the blocking status of netconn calls (@todo: write/send is missing) */ -#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0) - -/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ -#define netconn_set_noautorecved(conn, val) do { if(val) { \ - (conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \ -} else { \ - (conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0) -/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ -#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0) - -#if LWIP_SO_RCVTIMEO -/** Set the receive timeout in milliseconds */ -#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout)) -/** Get the receive timeout in milliseconds */ -#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout) -#endif /* LWIP_SO_RCVTIMEO */ -#if LWIP_SO_RCVBUF -/** Set the receive buffer in bytes */ -#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize)) -/** Get the receive buffer in bytes */ -#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize) -#endif /* LWIP_SO_RCVBUF*/ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_NETCONN */ - -#endif /* __LWIP_API_H__ */ diff --git a/tools/sdk/lwip/include/lwip/api_msg.h b/tools/sdk/lwip/include/lwip/api_msg.h deleted file mode 100644 index f99d8c3b7..000000000 --- a/tools/sdk/lwip/include/lwip/api_msg.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_API_MSG_H__ -#define __LWIP_API_MSG_H__ - -#include "lwip/opt.h" - -#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ - -#include /* for size_t */ - -#include "lwip/ip_addr.h" -#include "lwip/err.h" -#include "lwip/sys.h" -#include "lwip/igmp.h" -#include "lwip/api.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* For the netconn API, these values are use as a bitmask! */ -#define NETCONN_SHUT_RD 1 -#define NETCONN_SHUT_WR 2 -#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR) - -/* IP addresses and port numbers are expected to be in - * the same byte order as in the corresponding pcb. - */ -/** This struct includes everything that is necessary to execute a function - for a netconn in another thread context (mainly used to process netconns - in the tcpip_thread context to be thread safe). */ -struct api_msg_msg { - /** The netconn which to process - always needed: it includes the semaphore - which is used to block the application thread until the function finished. */ - struct netconn *conn; - /** The return value of the function executed in tcpip_thread. */ - err_t err; - /** Depending on the executed function, one of these union members is used */ - union { - /** used for do_send */ - struct netbuf *b; - /** used for do_newconn */ - struct { - u8_t proto; - } n; - /** used for do_bind and do_connect */ - struct { - ip_addr_t *ipaddr; - u16_t port; - } bc; - /** used for do_getaddr */ - struct { - ip_addr_t *ipaddr; - u16_t *port; - u8_t local; - } ad; - /** used for do_write */ - struct { - const void *dataptr; - size_t len; - u8_t apiflags; - } w; - /** used for do_recv */ - struct { - u32_t len; - } r; - /** used for do_close (/shutdown) */ - struct { - u8_t shut; - } sd; -#if LWIP_IGMP - /** used for do_join_leave_group */ - struct { - ip_addr_t *multiaddr; - ip_addr_t *netif_addr; - enum netconn_igmp join_or_leave; - } jl; -#endif /* LWIP_IGMP */ -#if TCP_LISTEN_BACKLOG - struct { - u8_t backlog; - } lb; -#endif /* TCP_LISTEN_BACKLOG */ - } msg; -}; - -/** This struct contains a function to execute in another thread context and - a struct api_msg_msg that serves as an argument for this function. - This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */ -struct api_msg { - /** function to execute in tcpip_thread context */ - void (* function)(struct api_msg_msg *msg); - /** arguments for this function */ - struct api_msg_msg msg; -}; - -#if LWIP_DNS -/** As do_gethostbyname requires more arguments but doesn't require a netconn, - it has its own struct (to avoid struct api_msg getting bigger than necessary). - do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg - (see netconn_gethostbyname). */ -struct dns_api_msg { - /** Hostname to query or dotted IP address string */ - const char *name; - /** Rhe resolved address is stored here */ - ip_addr_t *addr; - /** This semaphore is posted when the name is resolved, the application thread - should wait on it. */ - sys_sem_t *sem; - /** Errors are given back here */ - err_t *err; -}; -#endif /* LWIP_DNS */ - -void do_newconn ( struct api_msg_msg *msg); -void do_delconn ( struct api_msg_msg *msg); -void do_bind ( struct api_msg_msg *msg); -void do_connect ( struct api_msg_msg *msg); -void do_disconnect ( struct api_msg_msg *msg); -void do_listen ( struct api_msg_msg *msg); -void do_send ( struct api_msg_msg *msg); -void do_recv ( struct api_msg_msg *msg); -void do_write ( struct api_msg_msg *msg); -void do_getaddr ( struct api_msg_msg *msg); -void do_close ( struct api_msg_msg *msg); -void do_shutdown ( struct api_msg_msg *msg); -#if LWIP_IGMP -void do_join_leave_group( struct api_msg_msg *msg); -#endif /* LWIP_IGMP */ - -#if LWIP_DNS -void do_gethostbyname(void *arg); -#endif /* LWIP_DNS */ - -struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); -void netconn_free(struct netconn *conn); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_NETCONN */ - -#endif /* __LWIP_API_MSG_H__ */ diff --git a/tools/sdk/lwip/include/lwip/app/dhcpserver.h b/tools/sdk/lwip/include/lwip/app/dhcpserver.h deleted file mode 100644 index 63e762c6e..000000000 --- a/tools/sdk/lwip/include/lwip/app/dhcpserver.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef __DHCPS_H__ -#define __DHCPS_H__ - -#define USE_DNS - -typedef struct dhcps_state{ - sint16_t state; -} dhcps_state; - -typedef struct dhcps_msg { - uint8_t op, htype, hlen, hops; - uint8_t xid[4]; - uint16_t secs, flags; - uint8_t ciaddr[4]; - uint8_t yiaddr[4]; - uint8_t siaddr[4]; - uint8_t giaddr[4]; - uint8_t chaddr[16]; - uint8_t sname[64]; - uint8_t file[128]; - uint8_t options[312]; -}dhcps_msg; - -#ifndef LWIP_OPEN_SRC -struct dhcps_lease { - bool enable; - struct ip_addr start_ip; - struct ip_addr end_ip; -}; - -enum dhcps_offer_option{ - OFFER_START = 0x00, - OFFER_ROUTER = 0x01, - OFFER_END -}; -#endif - -typedef enum { - DHCPS_TYPE_DYNAMIC, - DHCPS_TYPE_STATIC -} dhcps_type_t; - -typedef enum { - DHCPS_STATE_ONLINE, - DHCPS_STATE_OFFLINE -} dhcps_state_t; - -struct dhcps_pool{ - struct ip_addr ip; - uint8 mac[6]; - uint32 lease_timer; - dhcps_type_t type; - dhcps_state_t state; - -}; - -typedef struct _list_node{ - void *pnode; - struct _list_node *pnext; -}list_node; - -extern uint32 dhcps_lease_time; -#define DHCPS_LEASE_TIMER dhcps_lease_time //0x05A0 -#define DHCPS_MAX_LEASE 0x64 -#define BOOTP_BROADCAST 0x8000 - -#define DHCP_REQUEST 1 -#define DHCP_REPLY 2 -#define DHCP_HTYPE_ETHERNET 1 -#define DHCP_HLEN_ETHERNET 6 -#define DHCP_MSG_LEN 236 - -#define DHCPS_SERVER_PORT 67 -#define DHCPS_CLIENT_PORT 68 - -#define DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPDECLINE 4 -#define DHCPACK 5 -#define DHCPNAK 6 -#define DHCPRELEASE 7 - -#define DHCP_OPTION_SUBNET_MASK 1 -#define DHCP_OPTION_ROUTER 3 -#define DHCP_OPTION_DNS_SERVER 6 -#define DHCP_OPTION_REQ_IPADDR 50 -#define DHCP_OPTION_LEASE_TIME 51 -#define DHCP_OPTION_MSG_TYPE 53 -#define DHCP_OPTION_SERVER_ID 54 -#define DHCP_OPTION_INTERFACE_MTU 26 -#define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31 -#define DHCP_OPTION_BROADCAST_ADDRESS 28 -#define DHCP_OPTION_REQ_LIST 55 -#define DHCP_OPTION_END 255 - -//#define USE_CLASS_B_NET 1 -#define DHCPS_DEBUG 0 -#define MAX_STATION_NUM 8 - -#define DHCPS_STATE_OFFER 1 -#define DHCPS_STATE_DECLINE 2 -#define DHCPS_STATE_ACK 3 -#define DHCPS_STATE_NAK 4 -#define DHCPS_STATE_IDLE 5 -#define DHCPS_STATE_RELEASE 6 - -#define dhcps_router_enabled(offer) ((offer & OFFER_ROUTER) != 0) - -void dhcps_start(struct ip_info *info); -void dhcps_stop(void); - -#endif - diff --git a/tools/sdk/lwip/include/lwip/app/espconn.h b/tools/sdk/lwip/include/lwip/app/espconn.h deleted file mode 100644 index 14fa9bcf9..000000000 --- a/tools/sdk/lwip/include/lwip/app/espconn.h +++ /dev/null @@ -1,686 +0,0 @@ -#ifndef __ESPCONN_H__ -#define __ESPCONN_H__ - -#include "lwip/dns.h" -#include "os_type.h" -#include "lwip/app/espconn_buf.h" - -#if 0 -#define espconn_printf(fmt, args...) os_printf(fmt,## args) -#else -#define espconn_printf(fmt, args...) -#endif - - -typedef void *espconn_handle; -typedef void (* espconn_connect_callback)(void *arg); -typedef void (* espconn_reconnect_callback)(void *arg, sint8 err); - -/* Definitions for error constants. */ - -#define ESPCONN_OK 0 /* No error, everything OK. */ -#define ESPCONN_MEM -1 /* Out of memory error. */ -#define ESPCONN_TIMEOUT -3 /* Timeout. */ -#define ESPCONN_RTE -4 /* Routing problem. */ -#define ESPCONN_INPROGRESS -5 /* Operation in progress */ -#define ESPCONN_MAXNUM -7 /* Total number exceeds the set maximum*/ - -#define ESPCONN_ABRT -8 /* Connection aborted. */ -#define ESPCONN_RST -9 /* Connection reset. */ -#define ESPCONN_CLSD -10 /* Connection closed. */ -#define ESPCONN_CONN -11 /* Not connected. */ - -#define ESPCONN_ARG -12 /* Illegal argument. */ -#define ESPCONN_IF -14 /* Low_level error */ -#define ESPCONN_ISCONN -15 /* Already connected. */ -#define ESPCONN_TIME -16 /* Sync Time error */ -#define ESPCONN_NODATA -17 /* No data can be read */ - -#define ESPCONN_HANDSHAKE -28 /* ssl handshake failed */ -#define ESPCONN_RESP_TIMEOUT -29 /* ssl handshake no response*/ -#define ESPCONN_PROTO_MSG -61 /* ssl application invalid */ - -#define ESPCONN_SSL 0x01 -#define ESPCONN_NORM 0x00 - -#define ESPCONN_STA 0x01 -#define ESPCONN_AP 0x02 -#define ESPCONN_AP_STA 0x03 - -#define STA_NETIF 0x00 -#define AP_NETIF 0x01 - -/** Protocol family and type of the espconn */ -enum espconn_type { - ESPCONN_INVALID = 0, - /* ESPCONN_TCP Group */ - ESPCONN_TCP = 0x10, - /* ESPCONN_UDP Group */ - ESPCONN_UDP = 0x20, -}; - -/** Current state of the espconn. Non-TCP espconn are always in state ESPCONN_NONE! */ -enum espconn_state { - ESPCONN_NONE, - ESPCONN_WAIT, - ESPCONN_LISTEN, - ESPCONN_CONNECT, - ESPCONN_WRITE, - ESPCONN_READ, - ESPCONN_CLOSE -}; - -typedef struct _esp_tcp { - int remote_port; - int local_port; - uint8 local_ip[4]; - uint8 remote_ip[4]; - espconn_connect_callback connect_callback; - espconn_reconnect_callback reconnect_callback; - espconn_connect_callback disconnect_callback; - espconn_connect_callback write_finish_fn; -} esp_tcp; - -typedef struct _esp_udp { - int remote_port; - int local_port; - uint8 local_ip[4]; - uint8 remote_ip[4]; -} esp_udp; - -typedef struct _remot_info{ - enum espconn_state state; - int remote_port; - uint8 remote_ip[4]; -}remot_info; - -/** A callback prototype to inform about events for a espconn */ -typedef void (* espconn_recv_callback)(void *arg, char *pdata, unsigned short len); -typedef void (* espconn_sent_callback)(void *arg); - -/** A espconn descriptor */ -struct espconn { - /** type of the espconn (TCP, UDP) */ - enum espconn_type type; - /** current state of the espconn */ - enum espconn_state state; - union { - esp_tcp *tcp; - esp_udp *udp; - } proto; - /** A callback function that is informed about events for this espconn */ - espconn_recv_callback recv_callback; - espconn_sent_callback sent_callback; - uint8 link_cnt; - void *reverse; -}; - -enum espconn_option{ - ESPCONN_START = 0x00, - ESPCONN_REUSEADDR = 0x01, - ESPCONN_NODELAY = 0x02, - ESPCONN_COPY = 0x04, - ESPCONN_KEEPALIVE = 0x08, - ESPCONN_END -}; - -enum espconn_level{ - ESPCONN_KEEPIDLE, - ESPCONN_KEEPINTVL, - ESPCONN_KEEPCNT -}; - -enum espconn_mode{ - ESPCONN_NOMODE, - ESPCONN_TCPSERVER_MODE, - ESPCONN_TCPCLIENT_MODE, - ESPCONN_UDP_MODE, - ESPCONN_NUM_MODE -}; - -struct espconn_packet{ - uint16 sent_length; /* sent length successful*/ - uint16 snd_buf_size; /* Available buffer size for sending */ - uint16 snd_queuelen; /* Available buffer space for sending */ - uint16 total_queuelen; /* total Available buffer space for sending */ - uint32 packseqno; /* seqno to be sent */ - uint32 packseq_nxt; /* seqno expected */ - uint32 packnum; -}; - -typedef struct _espconn_buf{ - uint8 *payload; - uint8 *punsent; - uint16 unsent; - uint16 len; - uint16 tot_len; - struct _espconn_buf *pnext; -} espconn_buf; - -typedef struct _comon_pkt{ - void *pcb; - int remote_port; - uint8 remote_ip[4]; - uint32 local_port; - uint32 local_ip; - espconn_buf *pbuf; - espconn_buf *ptail; - uint8* ptrbuf; - uint16 cntr; - sint8 err; - uint32 timeout; - uint32 recv_check; - uint8 pbuf_num; - struct espconn_packet packet_info; - bool write_flag; - enum espconn_option espconn_opt; -}comon_pkt; - -typedef struct _espconn_msg{ - struct espconn *pespconn; - comon_pkt pcommon; - uint8 count_opt; - uint8 espconn_mode; - sint16_t hs_status; //the status of the handshake - void *preverse; - void *pssl; - struct _espconn_msg *pnext; - -//***********Code for WIFI_BLOCK from upper************** - uint8 recv_hold_flag; - uint16 recv_holded_buf_Len; -//******************************************************* - ringbuf *readbuf; -}espconn_msg; - -#ifndef _MDNS_INFO -#define _MDNS_INFO -struct mdns_info { - char *host_name; - char *server_name; - uint16 server_port; - unsigned long ipAddr; - char *txt_data[10]; -}; -#endif - -#define linkMax 15 - -#define espconn_delay_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_NODELAY) != 0) -#define espconn_delay_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_NODELAY) == 0) -#define espconn_reuse_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_REUSEADDR) != 0) -#define espconn_copy_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_COPY) != 0) -#define espconn_copy_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_COPY) == 0) -#define espconn_keepalive_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_KEEPALIVE) != 0) -#define espconn_keepalive_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_KEEPALIVE) == 0) - -#define espconn_TaskPrio 26 -#define espconn_TaskQueueLen 15 - -enum espconn_sig { - SIG_ESPCONN_NONE, - SIG_ESPCONN_ERRER, - SIG_ESPCONN_LISTEN, - SIG_ESPCONN_CONNECT, - SIG_ESPCONN_WRITE, - SIG_ESPCONN_SEND, - SIG_ESPCONN_READ, - SIG_ESPCONN_CLOSE -}; - -/****************************************************************************** - * FunctionName : espconn_copy_partial - * Description : reconnect with host - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ - -void espconn_copy_partial(struct espconn *pesp_dest, struct espconn *pesp_source); - -/****************************************************************************** - * FunctionName : espconn_copy_partial - * Description : insert the node to the active connection list - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ - -void espconn_list_creat(espconn_msg **phead, espconn_msg* pinsert); - -/****************************************************************************** - * FunctionName : espconn_list_delete - * Description : remove the node from the active connection list - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ - -void espconn_list_delete(espconn_msg **phead, espconn_msg* pdelete); - -/****************************************************************************** - * FunctionName : espconn_find_connection - * Description : Initialize the server: set up a listening PCB and bind it to - * the defined port - * Parameters : espconn -- the espconn used to build server - * Returns : none - *******************************************************************************/ - -bool espconn_find_connection(struct espconn *pespconn, espconn_msg **pnode); - -/****************************************************************************** - * FunctionName : espconn_get_connection_info - * Description : used to specify the function that should be called when disconnect - * Parameters : espconn -- espconn to set the err callback - * discon_cb -- err callback function to call when err - * Returns : none -*******************************************************************************/ - -sint8 espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags); - -/****************************************************************************** - * FunctionName : espconn_get_packet_info - * Description : get the packet info with host - * Parameters : espconn -- the espconn used to disconnect the connection - * infoarg -- the packet info - * Returns : the errur code -*******************************************************************************/ - -sint8 espconn_get_packet_info(struct espconn *espconn, struct espconn_packet* infoarg); - -/****************************************************************************** - * FunctionName : espconn_connect - * Description : The function given as the connect - * Parameters : espconn -- the espconn used to listen the connection - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_connect(struct espconn *espconn); - -/****************************************************************************** - * FunctionName : espconn_disconnect - * Description : disconnect with host - * Parameters : espconn -- the espconn used to disconnect the connection - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_disconnect(struct espconn *espconn); - -/****************************************************************************** - * FunctionName : espconn_delete - * Description : disconnect with host - * Parameters : espconn -- the espconn used to disconnect the connection - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_delete(struct espconn *espconn); - -/****************************************************************************** - * FunctionName : espconn_accept - * Description : The function given as the listen - * Parameters : espconn -- the espconn used to listen the connection - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_accept(struct espconn *espconn); - -/****************************************************************************** - * FunctionName : espconn_create - * Description : sent data for client or server - * Parameters : espconn -- espconn to the data transmission - * Returns : result -*******************************************************************************/ - -extern sint8 espconn_create(struct espconn *espconn); - -/****************************************************************************** - * FunctionName : espconn_tcp_get_wnd - * Description : get the window size of simulatenously active TCP connections - * Parameters : none - * Returns : the number of TCP_MSS active TCP connections -*******************************************************************************/ -extern uint8 espconn_tcp_get_wnd(void); - -/****************************************************************************** - * FunctionName : espconn_tcp_set_max_con - * Description : set the window size simulatenously active TCP connections - * Parameters : num -- the number of TCP_MSS - * Returns : ESPCONN_ARG -- Illegal argument - * ESPCONN_OK -- No error -*******************************************************************************/ -extern sint8 espconn_tcp_set_wnd(uint8 num); - -/****************************************************************************** - * FunctionName : espconn_tcp_get_max_con - * Description : get the number of simulatenously active TCP connections - * Parameters : none - * Returns : none -*******************************************************************************/ - -extern uint8 espconn_tcp_get_max_con(void); - -/****************************************************************************** - * FunctionName : espconn_tcp_set_max_con - * Description : set the number of simulatenously active TCP connections - * Parameters : num -- total number - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_tcp_set_max_con(uint8 num); - -/****************************************************************************** - * FunctionName : espconn_tcp_get_max_retran - * Description : get the Maximum number of retransmissions of data active TCP connections - * Parameters : none - * Returns : the Maximum number of retransmissions -*******************************************************************************/ -extern uint8 espconn_tcp_get_max_retran(void); - -/****************************************************************************** - * FunctionName : espconn_tcp_set_max_retran - * Description : set the Maximum number of retransmissions of data active TCP connections - * Parameters : num -- the Maximum number of retransmissions - * Returns : result -*******************************************************************************/ - -extern sint8 espconn_tcp_set_max_retran(uint8 num); - -/****************************************************************************** - * FunctionName : espconn_tcp_get_max_syn - * Description : get the Maximum number of retransmissions of SYN segments - * Parameters : none - * Returns : the Maximum number of retransmissions -*******************************************************************************/ - -extern uint8 espconn_tcp_get_max_syn(void); - -/****************************************************************************** - * FunctionName : espconn_tcp_set_max_syn - * Description : set the Maximum number of retransmissions of SYN segments - * Parameters : num -- the Maximum number of retransmissions - * Returns : result -*******************************************************************************/ - -extern sint8 espconn_tcp_set_max_syn(uint8 num); - -/****************************************************************************** - * FunctionName : espconn_tcp_get_max_con_allow - * Description : get the count of simulatenously active connections on the server - * Parameters : espconn -- espconn to get the count - * Returns : result -*******************************************************************************/ - -extern sint8 espconn_tcp_get_max_con_allow(struct espconn *espconn); - -/****************************************************************************** - * FunctionName : espconn_tcp_set_max_con_allow - * Description : set the count of simulatenously active connections on the server - * Parameters : espconn -- espconn to set the count - * Returns : result -*******************************************************************************/ - -extern sint8 espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num); - -/****************************************************************************** - * FunctionName : espconn_tcp_set_buf_count - * Description : set the total number of espconn_buf on the unsent lists - * Parameters : espconn -- espconn to set the count - * num -- the total number of espconn_buf - * Returns : result -*******************************************************************************/ - -extern sint8 espconn_tcp_set_buf_count(struct espconn *espconn, uint8 num); - -/****************************************************************************** - * FunctionName : espconn_regist_time - * Description : used to specify the time that should be called when don't recv data - * Parameters : espconn -- the espconn used to the connection - * interval -- the timer when don't recv data - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag); - -/****************************************************************************** - * FunctionName : espconn_regist_sentcb - * Description : Used to specify the function that should be called when data - * has been successfully delivered to the remote host. - * Parameters : struct espconn *espconn -- espconn to set the sent callback - * espconn_sent_callback sent_cb -- sent callback function to - * call for this espconn when data is successfully sent - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb); - -/****************************************************************************** - * FunctionName : espconn_regist_sentcb - * Description : Used to specify the function that should be called when data - * has been successfully delivered to the remote host. - * Parameters : espconn -- espconn to set the sent callback - * sent_cb -- sent callback function to call for this espconn - * when data is successfully sent - * Returns : none -*******************************************************************************/ -extern sint8 espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn); - -/****************************************************************************** - * FunctionName : espconn_sent - * Description : sent data for client or server - * Parameters : espconn -- espconn to set for client or server - * psent -- data to send - * length -- length of data to send - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length); - -/****************************************************************************** - * FunctionName : espconn_regist_connectcb - * Description : used to specify the function that should be called when - * connects to host. - * Parameters : espconn -- espconn to set the connect callback - * connect_cb -- connected callback function to call when connected - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb); - -/****************************************************************************** - * FunctionName : espconn_regist_recvcb - * Description : used to specify the function that should be called when recv - * data from host. - * Parameters : espconn -- espconn to set the recv callback - * recv_cb -- recv callback function to call when recv data - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb); - -/****************************************************************************** - * FunctionName : espconn_regist_reconcb - * Description : used to specify the function that should be called when connection - * because of err disconnect. - * Parameters : espconn -- espconn to set the err callback - * recon_cb -- err callback function to call when err - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb); - -/****************************************************************************** - * FunctionName : espconn_regist_disconcb - * Description : used to specify the function that should be called when disconnect - * Parameters : espconn -- espconn to set the err callback - * discon_cb -- err callback function to call when err - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb); - -/****************************************************************************** - * FunctionName : espconn_port - * Description : access port value for client so that we don't end up bouncing - * all connections at the same time . - * Parameters : none - * Returns : access port value -*******************************************************************************/ - -extern uint32 espconn_port(void); - -/****************************************************************************** - * FunctionName : espconn_set_opt - * Description : access port value for client so that we don't end up bouncing - * all connections at the same time . - * Parameters : none - * Returns : access port value -*******************************************************************************/ -extern sint8 espconn_set_opt(struct espconn *espconn, uint8 opt); - -/****************************************************************************** - * FunctionName : espconn_set_keepalive - * Description : access level value for connection so that we set the value for - * keep alive - * Parameters : espconn -- the espconn used to set the connection - * level -- the connection's level - * value -- the value of time(s) - * Returns : access port value -*******************************************************************************/ -extern sint8 espconn_set_keepalive(struct espconn *espconn, uint8 level, void* optarg); - -/****************************************************************************** - * FunctionName : espconn_get_keepalive - * Description : access level value for connection so that we get the value for - * keep alive - * Parameters : espconn -- the espconn used to get the connection - * level -- the connection's level - * Returns : access keep alive value -*******************************************************************************/ -extern sint8 espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg); - -/****************************************************************************** - * FunctionName : espconn_gethostbyname - * Description : Resolve a hostname (string) into an IP address. - * Parameters : pespconn -- espconn to resolve a hostname - * hostname -- the hostname that is to be queried - * addr -- pointer to a ip_addr_t where to store the address if - * it is already cached in the dns_table (only valid if - * ESPCONN_OK is returned!) - * found -- a callback function to be called on success, failure - * or timeout (only if ERR_INPROGRESS is returned!) - * Returns : err_t return code - * - ESPCONN_OK if hostname is a valid IP address string or the host - * name is already in the local names table. - * - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server - * for resolution if no errors are present. - * - ESPCONN_ARG: dns client not initialized or invalid hostname -*******************************************************************************/ - -extern err_t espconn_gethostbyname(struct espconn *pespconn, const char *name, ip_addr_t *addr, dns_found_callback found); - -/****************************************************************************** - * FunctionName : espconn_igmp_join - * Description : join a multicast group - * Parameters : host_ip -- the ip address of udp server - * multicast_ip -- multicast ip given by user - * Returns : none -*******************************************************************************/ -extern sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip); - -/****************************************************************************** - * FunctionName : espconn_igmp_leave - * Description : leave a multicast group - * Parameters : host_ip -- the ip address of udp server - * multicast_ip -- multicast ip given by user - * Returns : none -*******************************************************************************/ -extern sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip); - -/****************************************************************************** - * FunctionName : espconn_mdns_init - * Description : register a device with mdns - * Parameters : ipAddr -- the ip address of device - * hostname -- the hostname of device - * Returns : none -*******************************************************************************/ -extern void espconn_mdns_init(struct mdns_info *info); -/****************************************************************************** - * FunctionName : espconn_mdns_init - * Description : close mdns socket - * Parameters : void - * Returns : none -*******************************************************************************/ -extern void espconn_mdns_close(void); -/****************************************************************************** - * FunctionName : mdns_server_register - * Description : register a server and join a multicast group - * Parameters : none - * Returns : none -*******************************************************************************/ -extern void espconn_mdns_server_register(void); -/****************************************************************************** - * FunctionName : mdns_server_register - * Description : unregister server and leave multicast group - * Parameters : none - * Returns : none -*******************************************************************************/ -extern void espconn_mdns_server_unregister(void); -/****************************************************************************** - * FunctionName : espconn_mdns_get_servername - * Description : get server name - * Parameters : none - * Returns : server name -*******************************************************************************/ -extern char* espconn_mdns_get_servername(void); -/****************************************************************************** - * FunctionName : espconn_mdns_get_servername - * Description : set server name - * Parameters : server name - * Returns : none -*******************************************************************************/ -extern void espconn_mdns_set_servername(const char *name); -/****************************************************************************** - * FunctionName : espconn_mdns_set_hostname - * Description : set host name - * Parameters : host name - * Returns : none -*******************************************************************************/ -extern void espconn_mdns_set_hostname(char *name); -/****************************************************************************** - * FunctionName : espconn_mdns_init - * Description : get host name - * Parameters : void - * Returns : hostname -*******************************************************************************/ -extern char* espconn_mdns_get_hostname(void); -/****************************************************************************** - * FunctionName : espconn_mdns_disable - * Description : join a multicast group - * Parameters : host_ip -- the ip address of udp server - * multicast_ip -- multicast ip given by user - * Returns : none -*******************************************************************************/ -extern void espconn_mdns_disable(void); -/****************************************************************************** - * FunctionName : espconn_mdns_enable - * Description : enable mdns - * Parameters : void - * Returns : none -*******************************************************************************/ -extern void espconn_mdns_enable(void); -/****************************************************************************** - * FunctionName : espconn_dns_setserver - * Description : Initialize one of the DNS servers. - * Parameters : numdns -- the index of the DNS server to set must - * be < DNS_MAX_SERVERS = 2 - * dnsserver -- IP address of the DNS server to set - * Returns : none -*******************************************************************************/ -extern void espconn_dns_setserver(u8_t numdns, ip_addr_t *dnsserver); -/****************************************************************************** - * FunctionName : espconn_dns_getserver - * Description : get dns server. - * Parameters : numdns -- the index of the DNS server ,must - * be < DNS_MAX_SERVERS = 2 - * Returns : dnsserver -- struct ip_addr_t -*******************************************************************************/ -extern ip_addr_t espconn_dns_getserver(u8_t numdns); -#endif - diff --git a/tools/sdk/lwip/include/lwip/app/espconn_buf.h b/tools/sdk/lwip/include/lwip/app/espconn_buf.h deleted file mode 100644 index 8bdfaa12a..000000000 --- a/tools/sdk/lwip/include/lwip/app/espconn_buf.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ringbuf.h - * - * Created on: Apr 22, 2016 - * Author: liuhan - */ - -#ifndef _ESPCONN_BUF_H_ -#define _ESPCONN_BUF_H_ - -/* - * ringbuffer.c - * - * Created on: Apr 22, 2016 - * Author: liuhan - */ -#include "c_types.h" - -#include "ets_sys.h" -#include "os_type.h" - -typedef struct ringbuf_t { - uint8_t *buf; - uint8_t *head, *tail; - size_t size; -} ringbuf, *ringbuf_t; - -ringbuf_t ringbuf_new(size_t capacity); - -size_t ringbuf_buffer_size(const struct ringbuf_t *rb); - -void ringbuf_reset(ringbuf_t rb); - -void ringbuf_free(ringbuf_t *rb); - -size_t ringbuf_capacity(const struct ringbuf_t *rb); - -size_t ringbuf_bytes_free(const struct ringbuf_t *rb); - -size_t ringbuf_bytes_used(const struct ringbuf_t *rb); - -int ringbuf_is_full(const struct ringbuf_t *rb); - -int ringbuf_is_empty(const struct ringbuf_t *rb); - -const void* ringbuf_tail(const struct ringbuf_t *rb); - -const void* ringbuf_head(const struct ringbuf_t *rb); - -static uint8_t *ringbuf_nextp(ringbuf_t rb, const uint8_t *p); - -size_t ringbuf_findchr(const struct ringbuf_t *rb, int c, size_t offset); - -size_t ringbuf_memset(ringbuf_t dst, int c, size_t len); - -void *ringbuf_memcpy_into(ringbuf_t dst, const void *src, size_t count); - -void *ringbuf_memcpy_from(void *dst, ringbuf_t src, size_t count); - -#endif /* RINGBUF_H_ */ diff --git a/tools/sdk/lwip/include/lwip/app/espconn_tcp.h b/tools/sdk/lwip/include/lwip/app/espconn_tcp.h deleted file mode 100644 index 5598a5cd3..000000000 --- a/tools/sdk/lwip/include/lwip/app/espconn_tcp.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef __ESPCONN_TCP_H__ -#define __ESPCONN_TCP_H__ - -#ifndef ESPCONN_TCP_DEBUG -#define ESPCONN_TCP_DEBUG LWIP_DBG_OFF -#endif -#include "lwip/app/espconn.h" - -#ifndef ESPCONN_TCP_TIMER -#define ESPCONN_TCP_TIMER 40 -#endif - -#define espconn_keepalive_enable(pcb) ((pcb)->so_options |= SOF_KEEPALIVE) -#define espconn_keepalive_disable(pcb) ((pcb)->so_options &= ~SOF_KEEPALIVE) - -/****************************************************************************** - * FunctionName : espconn_kill_oldest_pcb - * Description : A oldest incoming connection has been killed. - * Parameters : none - * Returns : none -*******************************************************************************/ - -extern void espconn_kill_oldest_pcb(void); - -/****************************************************************************** - * FunctionName : espconn_tcp_disconnect - * Description : A new incoming connection has been disconnected. - * Parameters : espconn -- the espconn used to disconnect with host - * Returns : none -*******************************************************************************/ - -extern void espconn_tcp_disconnect(espconn_msg *pdiscon,u8 type); - -/****************************************************************************** - * FunctionName : espconn_tcp_client - * Description : Initialize the client: set up a connect PCB and bind it to - * the defined port - * Parameters : espconn -- the espconn used to build client - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_tcp_client(struct espconn* espconn); - -/****************************************************************************** - * FunctionName : espconn_tcp_server - * Description : Initialize the server: set up a listening PCB and bind it to - * the defined port - * Parameters : espconn -- the espconn used to build server - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_tcp_server(struct espconn *espconn); - -#endif /* __CLIENT_TCP_H__ */ - diff --git a/tools/sdk/lwip/include/lwip/app/espconn_udp.h b/tools/sdk/lwip/include/lwip/app/espconn_udp.h deleted file mode 100644 index cdb312f73..000000000 --- a/tools/sdk/lwip/include/lwip/app/espconn_udp.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef __ESPCONN_UDP_H__ -#define __ESPCONN_UDP_H__ - -#ifndef ESPCONN_UDP_DEBUG -#define ESPCONN_UDP_DEBUG LWIP_DBG_OFF -#endif - -#include "lwip/app/espconn.h" - -/****************************************************************************** - * FunctionName : espconn_udp_client - * Description : Initialize the client: set up a PCB and bind it to the port - * Parameters : pespconn -- the espconn used to build client - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_udp_client(struct espconn *pespconn); - -/****************************************************************************** - * FunctionName : espconn_udp_disconnect - * Description : A new incoming connection has been disconnected. - * Parameters : espconn -- the espconn used to disconnect with host - * Returns : none -*******************************************************************************/ - -extern void espconn_udp_disconnect(espconn_msg *pdiscon); - -/****************************************************************************** - * FunctionName : espconn_udp_server - * Description : Initialize the server: set up a PCB and bind it to the port - * Parameters : pespconn -- the espconn used to build server - * Returns : none -*******************************************************************************/ - -extern sint8 espconn_udp_server(struct espconn *espconn); - -/****************************************************************************** - * FunctionName : espconn_udp_sent - * Description : sent data for client or server - * Parameters : void *arg -- client or server to send - * uint8* psent -- Data to send - * uint16 length -- Length of data to send - * Returns : none -*******************************************************************************/ - -extern err_t espconn_udp_sent(void *arg, uint8 *psent, uint16 length); - -/****************************************************************************** - * FunctionName : espconn_udp_sendto - * Description : sent data for UDP - * Parameters : void *arg -- UDP to send - * uint8* psent -- Data to send - * uint16 length -- Length of data to send - * Returns : return espconn error code. - * - ESPCONN_OK. Successful. No error occured. - * - ESPCONN_MEM. Out of memory. - * - ESPCONN_RTE. Could not find route to destination address. - * - More errors could be returned by lower protocol layers. -*******************************************************************************/ -extern err_t espconn_udp_sendto(void *arg, uint8 *psent, uint16 length); - -#endif /* __ESPCONN_UDP_H__ */ - - diff --git a/tools/sdk/lwip/include/lwip/app/ping.h b/tools/sdk/lwip/include/lwip/app/ping.h deleted file mode 100644 index 21e26e910..000000000 --- a/tools/sdk/lwip/include/lwip/app/ping.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef __PING_H__ -#define __PING_H__ -#include "lwip/ip_addr.h" -#include "lwip/icmp.h" -/** - * PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is used - */ -#ifndef PING_USE_SOCKETS -#define PING_USE_SOCKETS LWIP_SOCKET -#endif - -/** - * PING_DEBUG: Enable debugging for PING. - */ -#ifndef PING_DEBUG -#define PING_DEBUG LWIP_DBG_OFF -#endif - -/** ping receive timeout - in milliseconds */ -#ifndef PING_RCV_TIMEO -#define PING_RCV_TIMEO 1000 -#endif - -/** ping delay - in milliseconds */ -#ifndef PING_COARSE -#define PING_COARSE 1000 -#endif - -/** ping identifier - must fit on a u16_t */ -#ifndef PING_ID -#define PING_ID 0xAFAF -#endif - -/** ping additional data size to include in the packet */ -#ifndef PING_DATA_SIZE -#define PING_DATA_SIZE 32 -#endif - -/** ping result action - no default action */ -#ifndef PING_RESULT -#define PING_RESULT(ping_ok) -#endif - -#define DEFAULT_PING_MAX_COUNT 4 -#define PING_TIMEOUT_MS 1000 - -typedef void (* ping_recv_function)(void* arg, void *pdata); -typedef void (* ping_sent_function)(void* arg, void *pdata); - -struct ping_option{ - uint32 count; - uint32 ip; - uint32 coarse_time; - ping_recv_function recv_function; - ping_sent_function sent_function; - void* reverse; -}; - -struct ping_msg{ - struct ping_option *ping_opt; - struct raw_pcb *ping_pcb; - uint32 ping_start; - uint32 ping_sent; - uint32 timeout_count; - uint32 max_count; - uint32 sent_count; - uint32 coarse_time; -}; - -struct ping_resp{ - uint32 total_count; - uint32 resp_time; - uint32 seqno; - uint32 timeout_count; - uint32 bytes; - uint32 total_bytes; - uint32 total_time; - sint8 ping_err; -}; - -bool ping_start(struct ping_option *ping_opt); -bool ping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv); -bool ping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent); - -#endif /* __PING_H__ */ diff --git a/tools/sdk/lwip/include/lwip/app/time.h b/tools/sdk/lwip/include/lwip/app/time.h deleted file mode 100644 index 189d7d1f0..000000000 --- a/tools/sdk/lwip/include/lwip/app/time.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * time.h - * - * Created on: May 31, 2016 - * Author: liuhan - */ - -#ifndef TIME_H_ -#define TIME_H_ -#include "osapi.h" -#include "os_type.h" -#include "lwip/sntp.h" - -struct timeval { - unsigned long tv_sec; /* seconds */ - unsigned long tv_usec; /* and microseconds */ -}; - -/***************************RTC TIME OPTION***************************************/ -// daylight settings -// Base calculated with value obtained from NTP server (64 bits) -#define sntp_base (*((uint64_t*)RTC_STORE0)) -// Timer value when base was obtained -#define TIM_REF_SET(value) WRITE_PERI_REG(RTC_STORE2, value) -#define TIM_REF_GET() READ_PERI_REG(RTC_STORE2) - -// Setters and getters for CAL, TZ and DST. -#define RTC_CAL_SET(val) do {uint32 value = READ_PERI_REG(RTC_STORE3);\ - value |= ((val) & 0x0000FFFF);\ - WRITE_PERI_REG(RTC_STORE3, value);\ - }while(0) -#define RTC_DST_SET(val) do {uint32 value = READ_PERI_REG(RTC_STORE3);\ - value |= (((val)<<16) & 0x00010000);\ - WRITE_PERI_REG(RTC_STORE3, value);\ - }while(0) -#define RTC_TZ_SET(val) do {uint32 value = READ_PERI_REG(RTC_STORE3);\ - value |= (((val)<<24) & 0xFF000000);\ - WRITE_PERI_REG(RTC_STORE3, value);\ - }while(0) - -#define RTC_CAL_GET() (READ_PERI_REG(RTC_STORE3) & 0x0000FFFF) -#define RTC_DST_GET() ((READ_PERI_REG(RTC_STORE3) & 0x00010000)>>16) -#define RTC_TZ_GET() ((((int)READ_PERI_REG(RTC_STORE3)) & ((int)0xFF000000))>>24) -void system_update_rtc(time_t t, uint32_t us); -time_t sntp_get_rtc_time(sint32_t *us); - -int gettimeofday(struct timeval* t, void* timezone); -void updateTime(uint32 ms); -bool configTime(int timezone, int daylightOffset, char *server1, char *server2, char *server3, bool enable); -time_t time(time_t *t); -unsigned long millis(void); -unsigned long micros(void); -#endif /* TIME_H_ */ diff --git a/tools/sdk/lwip/include/lwip/arch.h b/tools/sdk/lwip/include/lwip/arch.h deleted file mode 100644 index 524af6be0..000000000 --- a/tools/sdk/lwip/include/lwip/arch.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_ARCH_H__ -#define __LWIP_ARCH_H__ - -#ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 1234 -#endif - -#ifndef BIG_ENDIAN -#define BIG_ENDIAN 4321 -#endif - -#include "arch/cc.h" - -/** Temporary: define format string for size_t if not defined in cc.h */ -#ifndef SZT_F -#define SZT_F U32_F -#endif /* SZT_F */ -/** Temporary upgrade helper: define format string for u8_t as hex if not - defined in cc.h */ -#ifndef X8_F -#define X8_F "02x" -#endif /* X8_F */ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef PACK_STRUCT_BEGIN -#define PACK_STRUCT_BEGIN -#endif /* PACK_STRUCT_BEGIN */ - -#ifndef PACK_STRUCT_END -#define PACK_STRUCT_END -#endif /* PACK_STRUCT_END */ - -#ifndef PACK_STRUCT_FIELD -#define PACK_STRUCT_FIELD(x) x -#endif /* PACK_STRUCT_FIELD */ - - -#ifndef LWIP_UNUSED_ARG -#define LWIP_UNUSED_ARG(x) (void)x -#endif /* LWIP_UNUSED_ARG */ - - -#ifdef LWIP_PROVIDE_ERRNO - -#define EPERM 1 /* Operation not permitted */ -#define ENOENT 2 /* No such file or directory */ -#define ESRCH 3 /* No such process */ -#define EINTR 4 /* Interrupted system call */ -#define EIO 5 /* I/O error */ -#define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Arg list too long */ -#define ENOEXEC 8 /* Exec format error */ -#define EBADF 9 /* Bad file number */ -#define ECHILD 10 /* No child processes */ -#define EAGAIN 11 /* Try again */ -#define ENOMEM 12 /* Out of memory */ -#define EACCES 13 /* Permission denied */ -#define EFAULT 14 /* Bad address */ -#define ENOTBLK 15 /* Block device required */ -#define EBUSY 16 /* Device or resource busy */ -#define EEXIST 17 /* File exists */ -#define EXDEV 18 /* Cross-device link */ -#define ENODEV 19 /* No such device */ -#define ENOTDIR 20 /* Not a directory */ -#define EISDIR 21 /* Is a directory */ -#define EINVAL 22 /* Invalid argument */ -#define ENFILE 23 /* File table overflow */ -#define EMFILE 24 /* Too many open files */ -#define ENOTTY 25 /* Not a typewriter */ -#define ETXTBSY 26 /* Text file busy */ -#define EFBIG 27 /* File too large */ -#define ENOSPC 28 /* No space left on device */ -#define ESPIPE 29 /* Illegal seek */ -#define EROFS 30 /* Read-only file system */ -#define EMLINK 31 /* Too many links */ -#define EPIPE 32 /* Broken pipe */ -#define EDOM 33 /* Math argument out of domain of func */ -#define ERANGE 34 /* Math result not representable */ -#define EDEADLK 35 /* Resource deadlock would occur */ -#define ENAMETOOLONG 36 /* File name too long */ -#define ENOLCK 37 /* No record locks available */ -#define ENOSYS 38 /* Function not implemented */ -#define ENOTEMPTY 39 /* Directory not empty */ -#define ELOOP 40 /* Too many symbolic links encountered */ -#define EWOULDBLOCK EAGAIN /* Operation would block */ -#define ENOMSG 42 /* No message of desired type */ -#define EIDRM 43 /* Identifier removed */ -#define ECHRNG 44 /* Channel number out of range */ -#define EL2NSYNC 45 /* Level 2 not synchronized */ -#define EL3HLT 46 /* Level 3 halted */ -#define EL3RST 47 /* Level 3 reset */ -#define ELNRNG 48 /* Link number out of range */ -#define EUNATCH 49 /* Protocol driver not attached */ -#define ENOCSI 50 /* No CSI structure available */ -#define EL2HLT 51 /* Level 2 halted */ -#define EBADE 52 /* Invalid exchange */ -#define EBADR 53 /* Invalid request descriptor */ -#define EXFULL 54 /* Exchange full */ -#define ENOANO 55 /* No anode */ -#define EBADRQC 56 /* Invalid request code */ -#define EBADSLT 57 /* Invalid slot */ - -#define EDEADLOCK EDEADLK - -#define EBFONT 59 /* Bad font file format */ -#define ENOSTR 60 /* Device not a stream */ -#define ENODATA 61 /* No data available */ -#define ETIME 62 /* Timer expired */ -#define ENOSR 63 /* Out of streams resources */ -#define ENONET 64 /* Machine is not on the network */ -#define ENOPKG 65 /* Package not installed */ -#define EREMOTE 66 /* Object is remote */ -#define ENOLINK 67 /* Link has been severed */ -#define EADV 68 /* Advertise error */ -#define ESRMNT 69 /* Srmount error */ -#define ECOMM 70 /* Communication error on send */ -#define EPROTO 71 /* Protocol error */ -#define EMULTIHOP 72 /* Multihop attempted */ -#define EDOTDOT 73 /* RFS specific error */ -#define EBADMSG 74 /* Not a data message */ -#define EOVERFLOW 75 /* Value too large for defined data type */ -#define ENOTUNIQ 76 /* Name not unique on network */ -#define EBADFD 77 /* File descriptor in bad state */ -#define EREMCHG 78 /* Remote address changed */ -#define ELIBACC 79 /* Can not access a needed shared library */ -#define ELIBBAD 80 /* Accessing a corrupted shared library */ -#define ELIBSCN 81 /* .lib section in a.out corrupted */ -#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ -#define ELIBEXEC 83 /* Cannot exec a shared library directly */ -#define EILSEQ 84 /* Illegal byte sequence */ -#define ERESTART 85 /* Interrupted system call should be restarted */ -#define ESTRPIPE 86 /* Streams pipe error */ -#define EUSERS 87 /* Too many users */ -#define ENOTSOCK 88 /* Socket operation on non-socket */ -#define EDESTADDRREQ 89 /* Destination address required */ -#define EMSGSIZE 90 /* Message too long */ -#define EPROTOTYPE 91 /* Protocol wrong type for socket */ -#define ENOPROTOOPT 92 /* Protocol not available */ -#define EPROTONOSUPPORT 93 /* Protocol not supported */ -#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ -#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ -#define EPFNOSUPPORT 96 /* Protocol family not supported */ -#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ -#define EADDRINUSE 98 /* Address already in use */ -#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ -#define ENETDOWN 100 /* Network is down */ -#define ENETUNREACH 101 /* Network is unreachable */ -#define ENETRESET 102 /* Network dropped connection because of reset */ -#define ECONNABORTED 103 /* Software caused connection abort */ -#define ECONNRESET 104 /* Connection reset by peer */ -#define ENOBUFS 105 /* No buffer space available */ -#define EISCONN 106 /* Transport endpoint is already connected */ -#define ENOTCONN 107 /* Transport endpoint is not connected */ -#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ -#define ETOOMANYREFS 109 /* Too many references: cannot splice */ -#define ETIMEDOUT 110 /* Connection timed out */ -#define ECONNREFUSED 111 /* Connection refused */ -#define EHOSTDOWN 112 /* Host is down */ -#define EHOSTUNREACH 113 /* No route to host */ -#define EALREADY 114 /* Operation already in progress */ -#define EINPROGRESS 115 /* Operation now in progress */ -#define ESTALE 116 /* Stale NFS file handle */ -#define EUCLEAN 117 /* Structure needs cleaning */ -#define ENOTNAM 118 /* Not a XENIX named type file */ -#define ENAVAIL 119 /* No XENIX semaphores available */ -#define EISNAM 120 /* Is a named type file */ -#define EREMOTEIO 121 /* Remote I/O error */ -#define EDQUOT 122 /* Quota exceeded */ - -#define ENOMEDIUM 123 /* No medium found */ -#define EMEDIUMTYPE 124 /* Wrong medium type */ - - -#define ENSROK 0 /* DNS server returned answer with no data */ -#define ENSRNODATA 160 /* DNS server returned answer with no data */ -#define ENSRFORMERR 161 /* DNS server claims query was misformatted */ -#define ENSRSERVFAIL 162 /* DNS server returned general failure */ -#define ENSRNOTFOUND 163 /* Domain name not found */ -#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */ -#define ENSRREFUSED 165 /* DNS server refused query */ -#define ENSRBADQUERY 166 /* Misformatted DNS query */ -#define ENSRBADNAME 167 /* Misformatted domain name */ -#define ENSRBADFAMILY 168 /* Unsupported address family */ -#define ENSRBADRESP 169 /* Misformatted DNS reply */ -#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */ -#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */ -#define ENSROF 172 /* End of file */ -#define ENSRFILE 173 /* Error reading file */ -#define ENSRNOMEM 174 /* Out of memory */ -#define ENSRDESTRUCTION 175 /* Application terminated lookup */ -#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */ -#define ENSRCNAMELOOP 177 /* Domain name is too long */ - -#ifndef errno -extern int errno; -#endif - -#endif /* LWIP_PROVIDE_ERRNO */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_ARCH_H__ */ diff --git a/tools/sdk/lwip/include/lwip/autoip.h b/tools/sdk/lwip/include/lwip/autoip.h deleted file mode 100644 index 23c264a1e..000000000 --- a/tools/sdk/lwip/include/lwip/autoip.h +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @file - * - * AutoIP Automatic LinkLocal IP Configuration - */ - -/* - * - * Copyright (c) 2007 Dominik Spies - * 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: Dominik Spies - * - * 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 - * - */ - -#ifndef __LWIP_AUTOIP_H__ -#define __LWIP_AUTOIP_H__ - -#include "lwip/opt.h" - -#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/netif.h" -#include "lwip/udp.h" -#include "netif/etharp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* AutoIP Timing */ -#define AUTOIP_TMR_INTERVAL 100 -#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL) - -/* RFC 3927 Constants */ -#define PROBE_WAIT 1 /* second (initial random delay) */ -#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */ -#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */ -#define PROBE_NUM 3 /* (number of probe packets) */ -#define ANNOUNCE_NUM 2 /* (number of announcement packets) */ -#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */ -#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */ -#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */ -#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */ -#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */ - -/* AutoIP client states */ -#define AUTOIP_STATE_OFF 0 -#define AUTOIP_STATE_PROBING 1 -#define AUTOIP_STATE_ANNOUNCING 2 -#define AUTOIP_STATE_BOUND 3 - -struct autoip -{ - ip_addr_t llipaddr; /* the currently selected, probed, announced or used LL IP-Address */ - u8_t state; /* current AutoIP state machine state */ - u8_t sent_num; /* sent number of probes or announces, dependent on state */ - u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ - u8_t lastconflict; /* ticks until a conflict can be solved by defending */ - u8_t tried_llipaddr; /* total number of probed/used Link Local IP-Addresses */ -}; - - -/** Init srand, has to be called before entering mainloop */ -void autoip_init(void); - -/** Set a struct autoip allocated by the application to work with */ -void autoip_set_struct(struct netif *netif, struct autoip *autoip); - -/** Start AutoIP client */ -err_t autoip_start(struct netif *netif); - -/** Stop AutoIP client */ -err_t autoip_stop(struct netif *netif); - -/** Handles every incoming ARP Packet, called by etharp_arp_input */ -void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); - -/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */ -void autoip_tmr(void); - -/** Handle a possible change in the network configuration */ -void autoip_network_changed(struct netif *netif); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_AUTOIP */ - -#endif /* __LWIP_AUTOIP_H__ */ diff --git a/tools/sdk/lwip/include/lwip/debug.h b/tools/sdk/lwip/include/lwip/debug.h deleted file mode 100644 index 1950a3e2e..000000000 --- a/tools/sdk/lwip/include/lwip/debug.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_DEBUG_H__ -#define __LWIP_DEBUG_H__ - -#include "lwip/arch.h" - -/** lower two bits indicate debug level - * - 0 all - * - 1 warning - * - 2 serious - * - 3 severe - */ -#define LWIP_DBG_LEVEL_ALL 0x00 -#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */ -#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */ -#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */ -#define LWIP_DBG_LEVEL_SEVERE 0x03 -#define LWIP_DBG_MASK_LEVEL 0x03 - -/** flag for LWIP_DEBUGF to enable that debug message */ -#define LWIP_DBG_ON 0x80U -/** flag for LWIP_DEBUGF to disable that debug message */ -#define LWIP_DBG_OFF 0x00U - -/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ -#define LWIP_DBG_TRACE 0x40U -/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ -#define LWIP_DBG_STATE 0x20U -/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ -#define LWIP_DBG_FRESH 0x10U -/** flag for LWIP_DEBUGF to halt after printing this debug message */ -#define LWIP_DBG_HALT 0x08U - -#ifndef LWIP_NOASSERT -#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \ - { LWIP_PLATFORM_ASSERT(message); } } while(0) -#else /* LWIP_NOASSERT */ -#define LWIP_ASSERT(message, assertion) -#endif /* LWIP_NOASSERT */ - -/** if "expression" isn't true, then print "message" and execute "handler" expression */ -#ifndef LWIP_ERROR -#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ - LWIP_PLATFORM_ASSERT(message); handler;}} while(0) -#endif /* LWIP_ERROR */ - -#ifdef LWIP_DEBUG -/** print debug message only if debug message type is enabled... - * AND is of correct type AND is at least LWIP_DBG_LEVEL - */ -#define LWIP_DEBUGF(debug, message) do { \ - if ( \ - ((debug) & LWIP_DBG_ON) && \ - ((debug) & LWIP_DBG_TYPES_ON) && \ - ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ - LWIP_PLATFORM_DIAG(message); \ - if ((debug) & LWIP_DBG_HALT) { \ - while(1); \ - } \ - } \ - } while(0) - -#else /* LWIP_DEBUG */ -#define LWIP_DEBUGF(debug, message) -#endif /* LWIP_DEBUG */ - -#endif /* __LWIP_DEBUG_H__ */ - diff --git a/tools/sdk/lwip/include/lwip/def.h b/tools/sdk/lwip/include/lwip/def.h deleted file mode 100644 index 9b6de6a8b..000000000 --- a/tools/sdk/lwip/include/lwip/def.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_DEF_H__ -#define __LWIP_DEF_H__ - -/* arch.h might define NULL already */ -#include "lwip/arch.h" -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y)) -#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y)) - -#ifndef NULL -#define NULL ((void *)0) -#endif - -/** Get the absolute difference between 2 u32_t values (correcting overflows) - * 'a' is expected to be 'higher' (without overflow) than 'b'. */ -#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1))) - -/* Endianess-optimized shifting of two u8_t to create one u16_t */ -#if BYTE_ORDER == LITTLE_ENDIAN -#define LWIP_MAKE_U16(a, b) ((a << 8) | b) -#else -#define LWIP_MAKE_U16(a, b) ((b << 8) | a) -#endif - -#ifndef LWIP_PLATFORM_BYTESWAP -#define LWIP_PLATFORM_BYTESWAP 0 -#endif - -#ifndef LWIP_PREFIX_BYTEORDER_FUNCS -/* workaround for naming collisions on some platforms */ - -#ifdef htons -#undef htons -#endif /* htons */ -#ifdef htonl -#undef htonl -#endif /* htonl */ -#ifdef ntohs -#undef ntohs -#endif /* ntohs */ -#ifdef ntohl -#undef ntohl -#endif /* ntohl */ - -#define htons(x) lwip_htons(x) -#define ntohs(x) lwip_ntohs(x) -#define htonl(x) lwip_htonl(x) -#define ntohl(x) lwip_ntohl(x) -#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */ - -#if BYTE_ORDER == BIG_ENDIAN -#define lwip_htons(x) (x) -#define lwip_ntohs(x) (x) -#define lwip_htonl(x) (x) -#define lwip_ntohl(x) (x) -#define PP_HTONS(x) (x) -#define PP_NTOHS(x) (x) -#define PP_HTONL(x) (x) -#define PP_NTOHL(x) (x) -#else /* BYTE_ORDER != BIG_ENDIAN */ -#if LWIP_PLATFORM_BYTESWAP -#define lwip_htons(x) LWIP_PLATFORM_HTONS(x) -#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x) -#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x) -#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x) -#else /* LWIP_PLATFORM_BYTESWAP */ -u16_t lwip_htons(u16_t x); -u16_t lwip_ntohs(u16_t x); -u32_t lwip_htonl(u32_t x); -u32_t lwip_ntohl(u32_t x); -#endif /* LWIP_PLATFORM_BYTESWAP */ - -/* These macros should be calculated by the preprocessor and are used - with compile-time constants only (so that there is no little-endian - overhead at runtime). */ -#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) -#define PP_NTOHS(x) PP_HTONS(x) -#define PP_HTONL(x) ((((x) & 0xff) << 24) | \ - (((x) & 0xff00) << 8) | \ - (((x) & 0xff0000UL) >> 8) | \ - (((x) & 0xff000000UL) >> 24)) -#define PP_NTOHL(x) PP_HTONL(x) - -#endif /* BYTE_ORDER == BIG_ENDIAN */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_DEF_H__ */ - diff --git a/tools/sdk/lwip/include/lwip/dhcp.h b/tools/sdk/lwip/include/lwip/dhcp.h deleted file mode 100644 index 9e8fd0ec2..000000000 --- a/tools/sdk/lwip/include/lwip/dhcp.h +++ /dev/null @@ -1,252 +0,0 @@ -/** @file - */ - -#ifndef __LWIP_DHCP_H__ -#define __LWIP_DHCP_H__ - -#include "lwip/opt.h" - -#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/netif.h" -#include "lwip/udp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** period (in seconds) of the application calling dhcp_coarse_tmr() */ -#define DHCP_COARSE_TIMER_SECS 60 -/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ -#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) -/** period (in milliseconds) of the application calling dhcp_fine_tmr() */ -#define DHCP_FINE_TIMER_MSECS 500 - -#define DHCP_CHADDR_LEN 16U -#define DHCP_SNAME_LEN 64U -#define DHCP_FILE_LEN 128U - -struct dhcp -{ - /** transaction identifier of last sent request */ - u32_t xid; - /** our connection to the DHCP server */ - struct udp_pcb *pcb; - /** incoming msg */ - struct dhcp_msg *msg_in; - /** current DHCP state machine state */ - u8_t state; - /** retries of current request */ - u8_t tries; -#if LWIP_DHCP_AUTOIP_COOP - u8_t autoip_coop_state; -#endif - u8_t subnet_mask_given; - - struct pbuf *p_out; /* pbuf of outcoming msg */ - struct dhcp_msg *msg_out; /* outgoing msg */ - u16_t options_out_len; /* outgoing msg options length */ - u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ - u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ - u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ - ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */ - ip_addr_t offered_ip_addr; - ip_addr_t offered_sn_mask; - ip_addr_t offered_gw_addr; - - u32_t offered_t0_lease; /* lease period (in seconds) */ - u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */ - u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */ - /* @todo: LWIP_DHCP_BOOTP_FILE configuration option? - integrate with possible TFTP-client for booting? */ -#define LWIP_DHCP_BOOTP_FILE 0 -#if LWIP_DHCP_BOOTP_FILE - ip_addr_t offered_si_addr; - char boot_file_name[DHCP_FILE_LEN]; -#endif /* LWIP_DHCP_BOOTPFILE */ -}; - -/* MUST be compiled with "pack structs" or equivalent! */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** minimum set of fields of any DHCP message */ -struct dhcp_msg -{ - PACK_STRUCT_FIELD(u8_t op); - PACK_STRUCT_FIELD(u8_t htype); - PACK_STRUCT_FIELD(u8_t hlen); - PACK_STRUCT_FIELD(u8_t hops); - PACK_STRUCT_FIELD(u32_t xid); - PACK_STRUCT_FIELD(u16_t secs); - PACK_STRUCT_FIELD(u16_t flags); - PACK_STRUCT_FIELD(ip_addr_p_t ciaddr); - PACK_STRUCT_FIELD(ip_addr_p_t yiaddr); - PACK_STRUCT_FIELD(ip_addr_p_t siaddr); - PACK_STRUCT_FIELD(ip_addr_p_t giaddr); - PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]); - PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]); - PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]); - PACK_STRUCT_FIELD(u32_t cookie); -#define DHCP_MIN_OPTIONS_LEN 68U -/** make sure user does not configure this too small */ -#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN)) -# undef DHCP_OPTIONS_LEN -#endif -/** allow this to be configured in lwipopts.h, but not too small */ -#if (!defined(DHCP_OPTIONS_LEN)) -/** set this to be sufficient for your options in outgoing DHCP msgs */ -# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN -#endif - PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp); -/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */ -#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0) -void dhcp_cleanup(struct netif *netif); -/** start DHCP configuration */ -err_t dhcp_start(struct netif *netif); -/** enforce early lease renewal (not needed normally)*/ -err_t dhcp_renew(struct netif *netif); -/** release the DHCP lease, usually called before dhcp_stop()*/ -err_t dhcp_release(struct netif *netif); -/** stop DHCP configuration */ -void dhcp_stop(struct netif *netif); -/** inform server of our manual IP address */ -void dhcp_inform(struct netif *netif); -/** Handle a possible change in the network configuration */ -void dhcp_network_changed(struct netif *netif); - -/** if enabled, check whether the offered IP address is not in use, using ARP */ -#if DHCP_DOES_ARP_CHECK -void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr); -#endif - -/** to be called every minute */ -void dhcp_coarse_tmr(void); -/** to be called every half second */ -void dhcp_fine_tmr(void); - -/** DHCP message item offsets and length */ -#define DHCP_OP_OFS 0 -#define DHCP_HTYPE_OFS 1 -#define DHCP_HLEN_OFS 2 -#define DHCP_HOPS_OFS 3 -#define DHCP_XID_OFS 4 -#define DHCP_SECS_OFS 8 -#define DHCP_FLAGS_OFS 10 -#define DHCP_CIADDR_OFS 12 -#define DHCP_YIADDR_OFS 16 -#define DHCP_SIADDR_OFS 20 -#define DHCP_GIADDR_OFS 24 -#define DHCP_CHADDR_OFS 28 -#define DHCP_SNAME_OFS 44 -#define DHCP_FILE_OFS 108 -#define DHCP_MSG_LEN 236 - -#define DHCP_COOKIE_OFS DHCP_MSG_LEN -#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4) - -#define DHCP_CLIENT_PORT 68 -#define DHCP_SERVER_PORT 67 - -/** DHCP client states */ -#define DHCP_OFF 0 -#define DHCP_REQUESTING 1 -#define DHCP_INIT 2 -#define DHCP_REBOOTING 3 -#define DHCP_REBINDING 4 -#define DHCP_RENEWING 5 -#define DHCP_SELECTING 6 -#define DHCP_INFORMING 7 -#define DHCP_CHECKING 8 -#define DHCP_PERMANENT 9 -#define DHCP_BOUND 10 -/** not yet implemented #define DHCP_RELEASING 11 */ -#define DHCP_BACKING_OFF 12 - -/** AUTOIP cooperatation flags */ -#define DHCP_AUTOIP_COOP_STATE_OFF 0 -#define DHCP_AUTOIP_COOP_STATE_ON 1 - -#define DHCP_BOOTREQUEST 1 -#define DHCP_BOOTREPLY 2 - -/** DHCP message types */ -#define DHCP_DISCOVER 1 -#define DHCP_OFFER 2 -#define DHCP_REQUEST 3 -#define DHCP_DECLINE 4 -#define DHCP_ACK 5 -#define DHCP_NAK 6 -#define DHCP_RELEASE 7 -#define DHCP_INFORM 8 - -/** DHCP hardware type, currently only ethernet is supported */ -#define DHCP_HTYPE_ETH 1 - -#define DHCP_MAGIC_COOKIE 0x63825363UL - -/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */ - -/** BootP options */ -#define DHCP_OPTION_PAD 0 -#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */ -#define DHCP_OPTION_ROUTER 3 -#define DHCP_OPTION_DNS_SERVER 6 -#define DHCP_OPTION_HOSTNAME 12 -#define DHCP_OPTION_IP_TTL 23 -#define DHCP_OPTION_MTU 26 -#define DHCP_OPTION_BROADCAST 28 -#define DHCP_OPTION_TCP_TTL 37 -#define DHCP_OPTION_END 255 - -/**add options for support more router by liuHan**/ -#define DHCP_OPTION_DOMAIN_NAME 15 -#define DHCP_OPTION_PRD 31 -#define DHCP_OPTION_STATIC_ROUTER 33 -#define DHCP_OPTION_VSN 43 -#define DHCP_OPTION_NB_TINS 44 -#define DHCP_OPTION_NB_TINT 46 -#define DHCP_OPTION_NB_TIS 47 -#define DHCP_OPTION_CLASSLESS_STATIC_ROUTER 121 -/** DHCP options */ -#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */ -#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */ -#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */ - -#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ -#define DHCP_OPTION_MESSAGE_TYPE_LEN 1 - -#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */ -#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */ - -#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */ -#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2 - -#define DHCP_OPTION_T1 58 /* T1 renewal time */ -#define DHCP_OPTION_T2 59 /* T2 rebinding time */ -#define DHCP_OPTION_US 60 -#define DHCP_OPTION_CLIENT_ID 61 -#define DHCP_OPTION_TFTP_SERVERNAME 66 -#define DHCP_OPTION_BOOTFILE 67 - -/** possible combinations of overloading the file and sname fields with options */ -#define DHCP_OVERLOAD_NONE 0 -#define DHCP_OVERLOAD_FILE 1 -#define DHCP_OVERLOAD_SNAME 2 -#define DHCP_OVERLOAD_SNAME_FILE 3 - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_DHCP */ - -#endif /*__LWIP_DHCP_H__*/ diff --git a/tools/sdk/lwip/include/lwip/dns.h b/tools/sdk/lwip/include/lwip/dns.h deleted file mode 100644 index 6c7d9b073..000000000 --- a/tools/sdk/lwip/include/lwip/dns.h +++ /dev/null @@ -1,124 +0,0 @@ -/** - * lwip DNS resolver header file. - - * Author: Jim Pettinato - * April 2007 - - * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. - * - * 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. - */ - -#ifndef __LWIP_DNS_H__ -#define __LWIP_DNS_H__ - -#include "lwip/opt.h" - -#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** DNS timer period */ -#define DNS_TMR_INTERVAL 1000 - -/** DNS field TYPE used for "Resource Records" */ -#define DNS_RRTYPE_A 1 /* a host address */ -#define DNS_RRTYPE_NS 2 /* an authoritative name server */ -#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ -#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ -#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ -#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ -#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ -#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ -#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ -#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ -#define DNS_RRTYPE_WKS 11 /* a well known service description */ -#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ -#define DNS_RRTYPE_HINFO 13 /* host information */ -#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ -#define DNS_RRTYPE_MX 15 /* mail exchange */ -#define DNS_RRTYPE_TXT 16 /* text strings */ - -/** DNS field CLASS used for "Resource Records" */ -#define DNS_RRCLASS_IN 1 /* the Internet */ -#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ -#define DNS_RRCLASS_CH 3 /* the CHAOS class */ -#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ -#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ - -/* The size used for the next line is rather a hack, but it prevents including socket.h in all files - that include memp.h, and that would possibly break portability (since socket.h defines some types - and constants possibly already define by the OS). - Calculation rule: - sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */ -#define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1) - -#if DNS_LOCAL_HOSTLIST -/** struct used for local host-list */ -struct local_hostlist_entry { - /** static hostname */ - const char *name; - /** static host address in network byteorder */ - ip_addr_t addr; - struct local_hostlist_entry *next; -}; -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC -#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN -#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH -#endif -#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1)) -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ -#endif /* DNS_LOCAL_HOSTLIST */ - -/** Callback which is invoked when a hostname is found. - * A function of this type must be implemented by the application using the DNS resolver. - * @param name pointer to the name that was looked up. - * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname, - * or NULL if the name could not be found (or on any other error). - * @param callback_arg a user-specified callback argument passed to dns_gethostbyname -*/ -typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg); - -void dns_init(void); -void dns_tmr(void); -void dns_setserver(u8_t numdns, ip_addr_t *dnsserver); -ip_addr_t dns_getserver(u8_t numdns); -err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, - dns_found_callback found, void *callback_arg); - -#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC -int dns_local_removehost(const char *hostname, const ip_addr_t *addr); -err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr); -#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_DNS */ - -#endif /* __LWIP_DNS_H__ */ diff --git a/tools/sdk/lwip/include/lwip/err.h b/tools/sdk/lwip/include/lwip/err.h deleted file mode 100644 index cb69a9f49..000000000 --- a/tools/sdk/lwip/include/lwip/err.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_ERR_H__ -#define __LWIP_ERR_H__ - -#include "lwip/opt.h" -#include "lwip/arch.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Define LWIP_ERR_T in cc.h if you want to use - * a different type for your platform (must be signed). */ -#ifdef LWIP_ERR_T -typedef LWIP_ERR_T err_t; -#else /* LWIP_ERR_T */ -typedef s8_t err_t; -#endif /* LWIP_ERR_T*/ - -/* Definitions for error constants. */ - -#define ERR_OK 0 /* No error, everything OK. */ -#define ERR_MEM -1 /* Out of memory error. */ -#define ERR_BUF -2 /* Buffer error. */ -#define ERR_TIMEOUT -3 /* Timeout. */ -#define ERR_RTE -4 /* Routing problem. */ -#define ERR_INPROGRESS -5 /* Operation in progress */ -#define ERR_VAL -6 /* Illegal value. */ -#define ERR_WOULDBLOCK -7 /* Operation would block. */ - -#define ERR_IS_FATAL(e) ((e) < ERR_WOULDBLOCK) - -#define ERR_ABRT -8 /* Connection aborted. */ -#define ERR_RST -9 /* Connection reset. */ -#define ERR_CLSD -10 /* Connection closed. */ -#define ERR_CONN -11 /* Not connected. */ - -#define ERR_ARG -12 /* Illegal argument. */ - -#define ERR_USE -13 /* Address in use. */ - -#define ERR_IF -14 /* Low-level netif error */ -#define ERR_ISCONN -15 /* Already connected. */ - - -#ifdef LWIP_DEBUG -extern const char *lwip_strerr(err_t err)ICACHE_FLASH_ATTR; -#else -#define lwip_strerr(x) "" -#endif /* LWIP_DEBUG */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_ERR_H__ */ diff --git a/tools/sdk/lwip/include/lwip/icmp.h b/tools/sdk/lwip/include/lwip/icmp.h deleted file mode 100644 index 9bcb7bc43..000000000 --- a/tools/sdk/lwip/include/lwip/icmp.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_ICMP_H__ -#define __LWIP_ICMP_H__ - -#include "lwip/opt.h" -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ICMP_ER 0 /* echo reply */ -#define ICMP_DUR 3 /* destination unreachable */ -#define ICMP_SQ 4 /* source quench */ -#define ICMP_RD 5 /* redirect */ -#define ICMP_ECHO 8 /* echo */ -#define ICMP_TE 11 /* time exceeded */ -#define ICMP_PP 12 /* parameter problem */ -#define ICMP_TS 13 /* timestamp */ -#define ICMP_TSR 14 /* timestamp reply */ -#define ICMP_IRQ 15 /* information request */ -#define ICMP_IR 16 /* information reply */ - -enum icmp_dur_type { - ICMP_DUR_NET = 0, /* net unreachable */ - ICMP_DUR_HOST = 1, /* host unreachable */ - ICMP_DUR_PROTO = 2, /* protocol unreachable */ - ICMP_DUR_PORT = 3, /* port unreachable */ - ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */ - ICMP_DUR_SR = 5 /* source route failed */ -}; - -enum icmp_te_type { - ICMP_TE_TTL = 0, /* time to live exceeded in transit */ - ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */ -}; - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -/** This is the standard ICMP header only that the u32_t data - * is splitted to two u16_t like ICMP echo needs it. - * This header is also used for other ICMP types that do not - * use the data part. - * ¶¨ÒåICMP»ØËÍÇëÇó±¨ÎÄÊײ¿½á¹¹£¬ - * ÓÉÓÚËùÓÐICMP±¨ÎÄÊײ¿ÓкܴóÏàËÆÐÔ£¬ - * ¸Ã½á¹¹Í¬ÑùÊÊÓÃÓÚÆäËüICMP±¨ÎÄ¡£ - */ -PACK_STRUCT_BEGIN -struct icmp_echo_hdr { - PACK_STRUCT_FIELD(u8_t type); - PACK_STRUCT_FIELD(u8_t code); - PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FIELD(u16_t id); - PACK_STRUCT_FIELD(u16_t seqno); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -//¶ÁÈ¡ICMPÊײ¿ÖÐ×Ö¶Î -#define ICMPH_TYPE(hdr) ((hdr)->type) -#define ICMPH_CODE(hdr) ((hdr)->code) - -/** Combines type and code to an u16_t ÏòICMP±¨ÎÄÊײ¿×Ö¶ÎÖÐдÈëÏàÓ¦Öµ*/ -#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) -#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) - - -#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ - -void icmp_input(struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; -void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)ICACHE_FLASH_ATTR; -void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)ICACHE_FLASH_ATTR; - -#endif /* LWIP_ICMP */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_ICMP_H__ */ diff --git a/tools/sdk/lwip/include/lwip/igmp.h b/tools/sdk/lwip/include/lwip/igmp.h deleted file mode 100644 index f0c9dea3f..000000000 --- a/tools/sdk/lwip/include/lwip/igmp.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2002 CITEL 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. Neither the name of CITEL Technologies Ltd nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``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 CITEL TECHNOLOGIES OR CONTRIBUTORS 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 a contribution to the lwIP TCP/IP stack. - * The Swedish Institute of Computer Science and Adam Dunkels - * are specifically granted permission to redistribute this - * source code. -*/ - -#ifndef __LWIP_IGMP_H__ -#define __LWIP_IGMP_H__ - -#include "lwip/opt.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/pbuf.h" - -#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ - -#ifdef __cplusplus -extern "C" { -#endif - - -/* IGMP timer */ -#define IGMP_TMR_INTERVAL 100 /* Milliseconds */ -#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL) -#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL) - -/* MAC Filter Actions, these are passed to a netif's - * igmp_mac_filter callback function. */ -#define IGMP_DEL_MAC_FILTER 0 -#define IGMP_ADD_MAC_FILTER 1 - - -/** - * igmp group structure - there is - * a list of groups for each interface - * these should really be linked from the interface, but - * if we keep them separate we will not affect the lwip original code - * too much - * - * There will be a group for the all systems group address but this - * will not run the state machine as it is used to kick off reports - * from all the other groups - */ -struct igmp_group { - /** next link */ - struct igmp_group *next; - /** interface on which the group is active */ - struct netif *netif; - /** multicast address */ - ip_addr_t group_address; - /** signifies we were the last person to report */ - u8_t last_reporter_flag; - /** current state of the group */ - u8_t group_state; - /** timer for reporting, negative is OFF */ - u16_t timer; - /** counter of simultaneous uses */ - u8_t use; -}; - -/* Prototypes */ -void igmp_init(void)ICACHE_FLASH_ATTR; -err_t igmp_start(struct netif *netif)ICACHE_FLASH_ATTR; -err_t igmp_stop(struct netif *netif)ICACHE_FLASH_ATTR; -void igmp_report_groups(struct netif *netif)ICACHE_FLASH_ATTR; -struct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)ICACHE_FLASH_ATTR; -void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)ICACHE_FLASH_ATTR; -err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR; -err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR; -void igmp_tmr(void)ICACHE_FLASH_ATTR; -#define LWIP_RAND() os_random() -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IGMP */ - -#endif /* __LWIP_IGMP_H__ */ diff --git a/tools/sdk/lwip/include/lwip/inet.h b/tools/sdk/lwip/include/lwip/inet.h deleted file mode 100644 index 7bff49b59..000000000 --- a/tools/sdk/lwip/include/lwip/inet.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_INET_H__ -#define __LWIP_INET_H__ - -#include "lwip/opt.h" -#include "lwip/def.h" -#include "lwip/ip_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** For compatibility with BSD code */ -struct in_addr { - u32_t s_addr; -}; - -/** 255.255.255.255 */ -#define INADDR_NONE IPADDR_NONE -/** 127.0.0.1 */ -#define INADDR_LOOPBACK IPADDR_LOOPBACK -/** 0.0.0.0 */ -#define INADDR_ANY IPADDR_ANY -/** 255.255.255.255 */ -#define INADDR_BROADCAST IPADDR_BROADCAST - -/* Definitions of the bits in an Internet address integer. - - On subnets, host and network parts are found according to - the subnet mask, not these masks. */ -#define IN_CLASSA(a) IP_CLASSA(a) -#define IN_CLASSA_NET IP_CLASSA_NET -#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT -#define IN_CLASSA_HOST IP_CLASSA_HOST -#define IN_CLASSA_MAX IP_CLASSA_MAX - -#define IN_CLASSB(b) IP_CLASSB(b) -#define IN_CLASSB_NET IP_CLASSB_NET -#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT -#define IN_CLASSB_HOST IP_CLASSB_HOST -#define IN_CLASSB_MAX IP_CLASSB_MAX - -#define IN_CLASSC(c) IP_CLASSC(c) -#define IN_CLASSC_NET IP_CLASSC_NET -#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT -#define IN_CLASSC_HOST IP_CLASSC_HOST -#define IN_CLASSC_MAX IP_CLASSC_MAX - -#define IN_CLASSD(d) IP_CLASSD(d) -#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */ -#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */ -#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */ -#define IN_CLASSD_MAX IP_CLASSD_MAX - -#define IN_MULTICAST(a) IP_MULTICAST(a) - -#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a) -#define IN_BADCLASS(a) IP_BADCLASS(a) - -#define IN_LOOPBACKNET IP_LOOPBACKNET - -#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) -#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) -/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */ -#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr)) - -/* directly map this to the lwip internal functions */ -#define inet_addr(cp) ipaddr_addr(cp) -#define inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)addr) -#define inet_ntoa(addr) ipaddr_ntoa((ip_addr_t*)&(addr)) -#define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen) - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_INET_H__ */ diff --git a/tools/sdk/lwip/include/lwip/inet_chksum.h b/tools/sdk/lwip/include/lwip/inet_chksum.h deleted file mode 100644 index 41be6415b..000000000 --- a/tools/sdk/lwip/include/lwip/inet_chksum.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_INET_CHKSUM_H__ -#define __LWIP_INET_CHKSUM_H__ - -#include "lwip/opt.h" - -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" - -/** Swap the bytes in an u16_t: much like htons() for little-endian */ -#ifndef SWAP_BYTES_IN_WORD -#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) -/* little endian and PLATFORM_BYTESWAP defined */ -#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w) -#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */ -/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */ -#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8) -#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/ -#endif /* SWAP_BYTES_IN_WORD */ - -/** Split an u32_t in two u16_ts and add them up */ -#ifndef FOLD_U32T -#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL)) -#endif - -#if LWIP_CHECKSUM_ON_COPY -/** Function-like macro: same as MEMCPY but returns the checksum of copied data - as u16_t */ -#ifndef LWIP_CHKSUM_COPY -#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len) -#ifndef LWIP_CHKSUM_COPY_ALGORITHM -#define LWIP_CHKSUM_COPY_ALGORITHM 1 -#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ -#endif /* LWIP_CHKSUM_COPY */ -#else /* LWIP_CHECKSUM_ON_COPY */ -#define LWIP_CHKSUM_COPY_ALGORITHM 0 -#endif /* LWIP_CHECKSUM_ON_COPY */ - -#ifdef __cplusplus -extern "C" { -#endif - -u16_t inet_chksum(void *dataptr, u16_t len)ICACHE_FLASH_ATTR; -u16_t inet_chksum_pbuf(struct pbuf *p)ICACHE_FLASH_ATTR; -u16_t inet_chksum_pseudo(struct pbuf *p, - ip_addr_t *src, ip_addr_t *dest, - u8_t proto, u16_t proto_len)ICACHE_FLASH_ATTR; -u16_t 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)ICACHE_FLASH_ATTR; -#if LWIP_CHKSUM_COPY_ALGORITHM -u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len)ICACHE_FLASH_ATTR; -#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_INET_H__ */ - diff --git a/tools/sdk/lwip/include/lwip/init.h b/tools/sdk/lwip/include/lwip/init.h deleted file mode 100644 index 7a58aece9..000000000 --- a/tools/sdk/lwip/include/lwip/init.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_INIT_H__ -#define __LWIP_INIT_H__ - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** X.x.x: Major version of the stack */ -#define LWIP_VERSION_MAJOR 1U -/** x.X.x: Minor version of the stack */ -#define LWIP_VERSION_MINOR 4U -/** x.x.X: Revision of the stack */ -#define LWIP_VERSION_REVISION 0U -/** For release candidates, this is set to 1..254 - * For official releases, this is set to 255 (LWIP_RC_RELEASE) - * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */ -#define LWIP_VERSION_RC 2U - -/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ -#define LWIP_RC_RELEASE 255U -/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */ -#define LWIP_RC_DEVELOPMENT 0U - -#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE) -#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT) -#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT)) - -/** Provides the version of the stack */ -#define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \ - LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC) - -/* Modules initialization */ -void lwip_init(void) ICACHE_FLASH_ATTR; -//void lwip_init(void); - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_INIT_H__ */ diff --git a/tools/sdk/lwip/include/lwip/ip.h b/tools/sdk/lwip/include/lwip/ip.h deleted file mode 100644 index 1f361fa44..000000000 --- a/tools/sdk/lwip/include/lwip/ip.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_IP_H__ -#define __LWIP_IP_H__ - -#include "lwip/opt.h" - -#include "lwip/def.h" -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" -#include "lwip/err.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Currently, the function ip_output_if_opt() is only used with IGMP */ -#define IP_OPTIONS_SEND LWIP_IGMP - -#define IP_HLEN 20 - -#define IP_PROTO_ICMP 1 -#define IP_PROTO_IGMP 2 -#define IP_PROTO_UDP 17 -#define IP_PROTO_UDPLITE 136 -#define IP_PROTO_TCP 6 - -/* This is passed as the destination address to ip_output_if (not - to ip_output), meaning that an IP header already is constructed - in the pbuf. This is used when TCP retransmits. */ -#ifdef IP_HDRINCL -#undef IP_HDRINCL -#endif /* IP_HDRINCL */ -#define IP_HDRINCL NULL - -#if LWIP_NETIF_HWADDRHINT -#define IP_PCB_ADDRHINT ;u8_t addr_hint -#else -#define IP_PCB_ADDRHINT -#endif /* LWIP_NETIF_HWADDRHINT */ - -/* This is the common part of all PCB types. It needs to be at the - beginning of a PCB type definition. It is located here so that - changes to this common part are made in one location instead of - having to change all PCB structs. */ -#define IP_PCB \ - /* ip addresses in network byte order */ \ - ip_addr_t local_ip; \ - ip_addr_t remote_ip; \ - /* Socket options */ \ - u8_t so_options; \ - /* Type Of Service */ \ - u8_t tos; \ - /* Time To Live */ \ - u8_t ttl \ - /* link layer address resolution hint */ \ - IP_PCB_ADDRHINT - -struct ip_pcb { -/* Common members of all PCB types */ - IP_PCB; -}; - -/* - * Option flags per-socket. These are the same like SO_XXX. - */ -/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */ -#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */ -#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */ -#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */ -/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */ -#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */ -#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */ -/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */ -/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */ - -/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ -#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/) - - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip_hdr { - /* version / header length / type of service */ - PACK_STRUCT_FIELD(u16_t _v_hl_tos); - /* total length */ - PACK_STRUCT_FIELD(u16_t _len); - /* identification */ - PACK_STRUCT_FIELD(u16_t _id); - /* fragment offset field */ - PACK_STRUCT_FIELD(u16_t _offset); -#define IP_RF 0x8000 /* reserved fragment flag */ -#define IP_DF 0x4000 /* dont fragment flag */ -#define IP_MF 0x2000 /* more fragments flag */ -#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ - /* time to live */ - PACK_STRUCT_FIELD(u8_t _ttl); - /* protocol*/ - PACK_STRUCT_FIELD(u8_t _proto); - /* checksum */ - PACK_STRUCT_FIELD(u16_t _chksum); - /* source and destination IP addresses */ - PACK_STRUCT_FIELD(ip_addr_p_t src); - PACK_STRUCT_FIELD(ip_addr_p_t dest); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12) -#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f) -#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff) -#define IPH_LEN(hdr) ((hdr)->_len) -#define IPH_ID(hdr) ((hdr)->_id) -#define IPH_OFFSET(hdr) ((hdr)->_offset) -#define IPH_TTL(hdr) ((hdr)->_ttl) -#define IPH_PROTO(hdr) ((hdr)->_proto) -#define IPH_CHKSUM(hdr) ((hdr)->_chksum) - -#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos))) -#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) -#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) -#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) -#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) -#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) -#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) - -/** The interface that provided the packet for the current callback invocation. */ -extern struct netif *current_netif; -/** Header of the input packet currently being processed. */ -extern const struct ip_hdr *current_header; -/** Source IP address of current_header */ -extern ip_addr_t current_iphdr_src; -/** Destination IP address of current_header */ -extern ip_addr_t current_iphdr_dest; - -#define ip_init() /* Compatibility define, not init needed. */ -struct netif *ip_route(ip_addr_t *dest)ICACHE_FLASH_ATTR; -struct netif *ip_router(ip_addr_t *dest, ip_addr_t *source); - -err_t ip_input(struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; -err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto)ICACHE_FLASH_ATTR; -err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, - struct netif *netif)ICACHE_FLASH_ATTR; -#if LWIP_NETIF_HWADDRHINT -err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)ICACHE_FLASH_ATTR; -#endif /* LWIP_NETIF_HWADDRHINT */ -#if IP_OPTIONS_SEND -err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, - u16_t optlen)ICACHE_FLASH_ATTR; -#endif /* IP_OPTIONS_SEND */ -/** Get the interface that received the current packet. - * This function must only be called from a receive callback (udp_recv, - * raw_recv, tcp_accept). It will return NULL otherwise. */ -#define ip_current_netif() (current_netif) -/** Get the IP header of the current packet. - * This function must only be called from a receive callback (udp_recv, - * raw_recv, tcp_accept). It will return NULL otherwise. */ -#define ip_current_header() (current_header) -/** Source IP address of current_header */ -#define ip_current_src_addr() (¤t_iphdr_src) -/** Destination IP address of current_header */ -#define ip_current_dest_addr() (¤t_iphdr_dest) - -#if IP_DEBUG -void ip_debug_print(struct pbuf *p)ICACHE_FLASH_ATTR; -#else -#define ip_debug_print(p) -#endif /* IP_DEBUG */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_IP_H__ */ - - diff --git a/tools/sdk/lwip/include/lwip/ip_addr.h b/tools/sdk/lwip/include/lwip/ip_addr.h deleted file mode 100644 index cfc10f809..000000000 --- a/tools/sdk/lwip/include/lwip/ip_addr.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_IP_ADDR_H__ -#define __LWIP_IP_ADDR_H__ - -#include "lwip/opt.h" -#include "lwip/def.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is the aligned version of ip_addr_t, - used as local variable, on the stack, etc. */ -struct ip_addr { - u32_t addr; -}; - -/* This is the packed version of ip_addr_t, - used in network headers that are itself packed */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip_addr_packed { - PACK_STRUCT_FIELD(u32_t addr); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** ip_addr_t uses a struct for convenience only, so that the same defines can - * operate both on ip_addr_t as well as on ip_addr_p_t. */ -typedef struct ip_addr ip_addr_t; -typedef struct ip_addr_packed ip_addr_p_t; - -/* - * struct ipaddr2 is used in the definition of the ARP packet format in - * order to support compilers that don't have structure packing. - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip_addr2 { - PACK_STRUCT_FIELD(u16_t addrw[2]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/* Forward declaration to not include netif.h */ -struct netif; - -extern const ip_addr_t ip_addr_any; -extern const ip_addr_t ip_addr_broadcast; - -/** IP_ADDR_ can be used as a fixed IP address - * for the wildcard and the broadcast address - */ -#define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any) -#define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast) - -/** 255.255.255.255 */ -#define IPADDR_NONE ((u32_t)0xffffffffUL) -/** 127.0.0.1 */ -#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL) -/** 0.0.0.0 */ -#define IPADDR_ANY ((u32_t)0x00000000UL) -/** 255.255.255.255 */ -#define IPADDR_BROADCAST ((u32_t)0xffffffffUL) - -/* Definitions of the bits in an Internet address integer. - - On subnets, host and network parts are found according to - the subnet mask, not these masks. */ -#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0) -#define IP_CLASSA_NET 0xff000000 -#define IP_CLASSA_NSHIFT 24 -#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET) -#define IP_CLASSA_MAX 128 - -#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) -#define IP_CLASSB_NET 0xffff0000 -#define IP_CLASSB_NSHIFT 16 -#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET) -#define IP_CLASSB_MAX 65536 - -#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) -#define IP_CLASSC_NET 0xffffff00 -#define IP_CLASSC_NSHIFT 8 -#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET) - -#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) -#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */ -#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */ -#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */ -#define IP_MULTICAST(a) IP_CLASSD(a) - -#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) -#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) - -#define IP_LOOPBACKNET 127 /* official! */ - - -#if BYTE_ORDER == BIG_ENDIAN -/** Set an IP address given by the four byte-parts */ -#define IP4_ADDR(ipaddr, a,b,c,d) \ - (ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \ - ((u32_t)((b) & 0xff) << 16) | \ - ((u32_t)((c) & 0xff) << 8) | \ - (u32_t)((d) & 0xff) -#else -/** Set an IP address given by the four byte-parts. - Little-endian version that prevents the use of htonl. */ -#define IP4_ADDR(ipaddr, a,b,c,d) \ - (ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \ - ((u32_t)((c) & 0xff) << 16) | \ - ((u32_t)((b) & 0xff) << 8) | \ - (u32_t)((a) & 0xff) -#endif - -/** MEMCPY-like copying of IP addresses where addresses are known to be - * 16-bit-aligned if the port is correctly configured (so a port could define - * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */ -#ifndef IPADDR2_COPY -#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t)) -#endif - -/** Copy IP address - faster than ip_addr_set: no NULL check */ -#define ip_addr_copy(dest, src) ((dest).addr = (src).addr) -/** Safely copy one IP address to another (src may be NULL) */ -#define ip_addr_set(dest, src) ((dest)->addr = \ - ((src) == NULL ? 0 : \ - (src)->addr)) -/** Set complete address to zero */ -#define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0) -/** Set address to IPADDR_ANY (no need for htonl()) */ -#define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY) -/** Set address to loopback address */ -#define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK)) -/** Safely copy one IP address to another and change byte order - * from host- to network-order. */ -#define ip_addr_set_hton(dest, src) ((dest)->addr = \ - ((src) == NULL ? 0:\ - htonl((src)->addr))) -/** IPv4 only: set the IP address given as an u32_t */ -#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32)) -/** IPv4 only: get the IP address as an u32_t */ -#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr) - -/** Get the network address by combining host address with netmask */ -#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr)) - -/** - * Determine if two address are on the same network. - * - * @arg addr1 IP address 1 - * @arg addr2 IP address 2 - * @arg mask network identifier mask - * @return !0 if the network identifiers of both address match - */ -#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ - (mask)->addr) == \ - ((addr2)->addr & \ - (mask)->addr)) -#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) - -#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY) - -#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif)) -u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)ICACHE_FLASH_ATTR; - -#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr) -u8_t ip4_addr_netmask_valid(u32_t netmask)ICACHE_FLASH_ATTR; - -#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL)) - -#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL)) - -#define ip_addr_debug_print(debug, ipaddr) \ - LWIP_DEBUGF(debug, ("%" U16_F ".%" U16_F ".%" U16_F ".%" U16_F, \ - ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0, \ - ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0, \ - ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0, \ - ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0)) - -/* Get one byte from the 4-byte address */ -#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0]) -#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1]) -#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2]) -#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3]) -/* These are cast to u16_t, with the intent that they are often arguments - * to printf using the U16_F format from cc.h. */ -#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr)) -#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr)) -#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr)) -#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr)) - -/** For backwards compatibility */ -#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr) - -u32_t ipaddr_addr(const char *cp)ICACHE_FLASH_ATTR; -int ipaddr_aton(const char *cp, ip_addr_t *addr)ICACHE_FLASH_ATTR; -/** returns ptr to static buffer; not reentrant! */ -char *ipaddr_ntoa(const ip_addr_t *addr)ICACHE_FLASH_ATTR; -char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)ICACHE_FLASH_ATTR; - -#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \ - ip4_addr2_16(ipaddr), \ - ip4_addr3_16(ipaddr), \ - ip4_addr4_16(ipaddr) - -#define IPSTR "%d.%d.%d.%d" - -struct ip_info { - struct ip_addr ip; - struct ip_addr netmask; - struct ip_addr gw; -}; -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_IP_ADDR_H__ */ diff --git a/tools/sdk/lwip/include/lwip/ip_frag.h b/tools/sdk/lwip/include/lwip/ip_frag.h deleted file mode 100644 index df6db5f5c..000000000 --- a/tools/sdk/lwip/include/lwip/ip_frag.h +++ /dev/null @@ -1,88 +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: Jani Monoses - * - */ - -#ifndef __LWIP_IP_FRAG_H__ -#define __LWIP_IP_FRAG_H__ - -#include "lwip/opt.h" -#include "lwip/err.h" -#include "lwip/pbuf.h" -#include "lwip/netif.h" -#include "lwip/ip_addr.h" -#include "lwip/ip.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if IP_REASSEMBLY -/* The IP reassembly timer interval in milliseconds. */ -#define IP_TMR_INTERVAL 1000 - -/* IP reassembly helper struct. - * This is exported because memp needs to know the size. - */ -struct ip_reassdata { - struct ip_reassdata *next; - struct pbuf *p; - struct ip_hdr iphdr; - u16_t datagram_len; - u8_t flags; - u8_t timer; -}; - -void ip_reass_init(void)ICACHE_FLASH_ATTR; -void ip_reass_tmr(void)ICACHE_FLASH_ATTR; -struct pbuf * ip_reass(struct pbuf *p)ICACHE_FLASH_ATTR; -#endif /* IP_REASSEMBLY */ - -#if IP_FRAG -#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF -/** A custom pbuf that holds a reference to another pbuf, which is freed - * when this custom pbuf is freed. This is used to create a custom PBUF_REF - * that points into the original pbuf. */ -struct pbuf_custom_ref { - /** 'base class' */ - struct pbuf_custom pc; - /** pointer to the original pbuf that is referenced */ - struct pbuf *original; -}; -#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ - -err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)ICACHE_FLASH_ATTR; -#endif /* IP_FRAG */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_IP_FRAG_H__ */ diff --git a/tools/sdk/lwip/include/lwip/mdns.h b/tools/sdk/lwip/include/lwip/mdns.h deleted file mode 100644 index 78546bc8b..000000000 --- a/tools/sdk/lwip/include/lwip/mdns.h +++ /dev/null @@ -1,114 +0,0 @@ -/** - * lwip MDNS resolver header file. - * - * Created on: Jul 29, 2010 - * Author: Daniel Toma - - - * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. - * - * 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. - */ - -#ifndef __LWIP_MDNS_H__ -#define __LWIP_MDNS_H__ - -#include "lwip/opt.h" - -#if LWIP_MDNS /* don't build if not configured for use in lwipopts.h */ - -/** DNS timer period */ -#define DNS_TMR_INTERVAL 1000 - -/** mDNS Address offset flag*/ -#define DNS_OFFSET_FLAG 0xC0 /* the offset flag in the DNS message */ -#define DNS_DEFAULT_OFFSET 0x0C /* the offset is set at the beginning of the DNS message */ - -#define DNS_IP_ADDR_LEN 4 - - -/** DNS field TYPE used for "Resource Records" */ -#define DNS_RRTYPE_A 1 /* a host address */ -#define DNS_RRTYPE_NS 2 /* an authoritative name server */ -#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ -#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ -#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ -#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ -#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ -#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ -#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ -#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ -#define DNS_RRTYPE_WKS 11 /* a well known service description */ -#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ -#define DNS_RRTYPE_HINFO 13 /* host information */ -#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ -#define DNS_RRTYPE_MX 15 /* mail exchange */ -#define DNS_RRTYPE_TXT 16 /* text strings */ -#define DNS_RRTYPE_SRV 33 /* Service record */ -#define DNS_RRTYPE_OPT 41 /* EDNS0 OPT record */ -#define DNS_RRTYPE_TSIG 250 /* Transaction Signature */ -#define DNS_RRTYPE_ANY 255 /*Not a DNS type, but a DNS query type, meaning "all types"*/ - -/* DNS field CLASS used for "Resource Records" */ -#define DNS_RRCLASS_IN 1 /* the Internet */ -#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ -#define DNS_RRCLASS_CH 3 /* the CHAOS class */ -#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ -#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ -#define DNS_RRCLASS_FLUSH_IN 0x8001/* Flush bit and Internet*/ - -/** Callback which is invoked when a hostname is found. - * A function of this type must be implemented by the application using the DNS resolver. - * @param name pointer to the name that was looked up. - * @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname, - * or NULL if the name could not be found (or on any other error). - * @param callback_arg a user-specified callback argument passed to dns_gethostbyname -*/ -#ifndef _MDNS_INFO -#define _MDNS_INFO -struct mdns_info { - char *host_name; - char *server_name; - uint16 server_port; - unsigned long ipAddr; - char *txt_data[10]; -}; -#endif -//void mdns_enable(void); -//void mdns_disable(void); -//void mdns_init(struct mdns_info *info); -//void mdns_close(void); -//char* mdns_get_hostname(void); -//void mdns_set_hostname(char *name); -//void mdns_set_servername(const char *name); -//char* mdns_get_servername(void); -//void mdns_server_unregister(void); -//void mdns_server_register(void) ; -//void mdns_tmr(void); -//void Delay(unsigned long ulSeconds); - -#endif /* LWIP_MDNS */ - -#endif /* __LWIP_MDNS_H__ */ diff --git a/tools/sdk/lwip/include/lwip/mem.h b/tools/sdk/lwip/include/lwip/mem.h deleted file mode 100644 index 3709bcdaa..000000000 --- a/tools/sdk/lwip/include/lwip/mem.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_MEM_H__ -#define __LWIP_MEM_H__ - -#include "lwip/opt.h" -//#include "mem_manager.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if MEM_LIBC_MALLOC - -#include /* for size_t */ - -typedef size_t mem_size_t; - -/* aliases for C library malloc() */ -#define mem_init() -/* in case C library malloc() needs extra protection, - * allow these defines to be overridden. - */ -#ifndef mem_free -#define mem_free(p) vPortFree(p, "", 0) -#endif -#ifndef mem_malloc -#define mem_malloc(s) pvPortMalloc(s, "", 0) -#endif -#ifndef mem_calloc -#define mem_calloc(s) pvPortCalloc(s, "", 0) -#endif -#ifndef mem_realloc -#define mem_realloc(p, s) pvPortRealloc(p, s, "", 0) -#endif -#ifndef mem_zalloc -#define mem_zalloc(s) pvPortZalloc(s, "", 0) -#endif - -#ifndef os_malloc -#define os_malloc(s) mem_malloc((s)) -#endif -#ifndef os_realloc -#define os_realloc(p, s) mem_realloc((p), (s)) -#endif -#ifndef os_zalloc -#define os_zalloc(s) mem_zalloc((s)) -#endif -#ifndef os_free -#define os_free(p) mem_free((p)) -#endif - -/* Since there is no C library allocation function to shrink memory without - moving it, define this to nothing. */ -#ifndef mem_trim -#define mem_trim(mem, size) (mem) -#endif -#else /* MEM_LIBC_MALLOC */ - -/* MEM_SIZE would have to be aligned, but using 64000 here instead of - * 65535 leaves some room for alignment... - */ -#if MEM_SIZE > 64000l -typedef u32_t mem_size_t; -#define MEM_SIZE_F U32_F -#else -typedef u16_t mem_size_t; -#define MEM_SIZE_F U16_F -#endif /* MEM_SIZE > 64000 */ - -#if MEM_USE_POOLS -/** mem_init is not used when using pools instead of a heap */ -#define mem_init() -/** mem_trim is not used when using pools instead of a heap: - we can't free part of a pool element and don't want to copy the rest */ -#define mem_trim(mem, size) (mem) -#else /* MEM_USE_POOLS */ -/* lwIP alternative malloc */ -void mem_init(void)ICACHE_FLASH_ATTR; -void *mem_trim(void *mem, mem_size_t size)ICACHE_FLASH_ATTR; -#endif /* MEM_USE_POOLS */ -void *mem_malloc(mem_size_t size)ICACHE_FLASH_ATTR; -void *mem_calloc(mem_size_t count, mem_size_t size)ICACHE_FLASH_ATTR; -void mem_free(void *mem)ICACHE_FLASH_ATTR; -#endif /* MEM_LIBC_MALLOC */ - -/** Calculate memory size for an aligned buffer - returns the next highest - * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and - * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). - */ -#ifndef LWIP_MEM_ALIGN_SIZE -#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1)) -#endif - -/** Calculate safe memory size for an aligned buffer when using an unaligned - * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the - * start (e.g. if buffer is u8_t[] and actual data will be u32_t*) - */ -#ifndef LWIP_MEM_ALIGN_BUFFER -#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1)) -#endif - -/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT - * so that ADDR % MEM_ALIGNMENT == 0 - */ -#ifndef LWIP_MEM_ALIGN -#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_MEM_H__ */ diff --git a/tools/sdk/lwip/include/lwip/memp.h b/tools/sdk/lwip/include/lwip/memp.h deleted file mode 100644 index 6a2127db2..000000000 --- a/tools/sdk/lwip/include/lwip/memp.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#ifndef __LWIP_MEMP_H__ -#define __LWIP_MEMP_H__ - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */ -typedef enum { -#define LWIP_MEMPOOL(name,num,size,desc, attr) MEMP_##name, -#include "lwip/memp_std.h" - MEMP_MAX -} memp_t; - -#if MEM_USE_POOLS -/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */ -typedef enum { - /* Get the first (via: - MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/ - MEMP_POOL_HELPER_FIRST = ((u8_t) -#define LWIP_MEMPOOL(name,num,size,desc) -#define LWIP_MALLOC_MEMPOOL_START 1 -#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0 -#define LWIP_MALLOC_MEMPOOL_END -#include "lwip/memp_std.h" - ) , - /* Get the last (via: - MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */ - MEMP_POOL_HELPER_LAST = ((u8_t) -#define LWIP_MEMPOOL(name,num,size,desc) -#define LWIP_MALLOC_MEMPOOL_START -#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size * -#define LWIP_MALLOC_MEMPOOL_END 1 -#include "lwip/memp_std.h" - ) -} memp_pool_helper_t; - -/* The actual start and stop values are here (cast them over) - We use this helper type and these defines so we can avoid using const memp_t values */ -#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST) -#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST) -#endif /* MEM_USE_POOLS */ - -#if MEMP_MEM_MALLOC || MEM_USE_POOLS -extern const u32_t memp_sizes[MEMP_MAX]; -#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */ - -#if MEMP_MEM_MALLOC - -#include "mem.h" - -#define memp_init() -#define memp_malloc(type) mem_malloc(memp_sizes[type]) -#define memp_free(type, mem) mem_free(mem) - -#else /* MEMP_MEM_MALLOC */ - -#if MEM_USE_POOLS -/** This structure is used to save the pool one element came from. */ -struct memp_malloc_helper -{ - memp_t poolnr; -}; -#endif /* MEM_USE_POOLS */ - -void memp_init(void)ICACHE_FLASH_ATTR; - -#if MEMP_OVERFLOW_CHECK -void *memp_malloc_fn(memp_t type, const char* file, const int line)ICACHE_FLASH_ATTR; -#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__) -#else -void *memp_malloc(memp_t type)ICACHE_FLASH_ATTR; -#endif -void memp_free(memp_t type, void *mem)ICACHE_FLASH_ATTR; - -#endif /* MEMP_MEM_MALLOC */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_MEMP_H__ */ diff --git a/tools/sdk/lwip/include/lwip/memp_std.h b/tools/sdk/lwip/include/lwip/memp_std.h deleted file mode 100644 index b20a24053..000000000 --- a/tools/sdk/lwip/include/lwip/memp_std.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * SETUP: Make sure we define everything we will need. - * - * We have create three types of pools: - * 1) MEMPOOL - standard pools - * 2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c - * 3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct - * - * If the include'r doesn't require any special treatment of each of the types - * above, then will declare #2 & #3 to be just standard mempools. - */ -#ifndef LWIP_MALLOC_MEMPOOL -/* This treats "malloc pools" just like any other pool. - The pools are a little bigger to provide 'size' as the amount of user data. */ -#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size, attr) -#define LWIP_MALLOC_MEMPOOL_START -#define LWIP_MALLOC_MEMPOOL_END -#endif /* LWIP_MALLOC_MEMPOOL */ - -#ifndef LWIP_PBUF_MEMPOOL -/* This treats "pbuf pools" just like any other pool. - * Allocates buffers for a pbuf struct AND a payload size */ -#define LWIP_PBUF_MEMPOOL(name, num, payload, desc, attr) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc, attr) -#endif /* LWIP_PBUF_MEMPOOL */ - - -/* - * A list of internal pools used by LWIP. - * - * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description) - * creates a pool name MEMP_pool_name. description is used in stats.c - */ -#if LWIP_RAW -LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB", DMEM_ATTR) -#endif /* LWIP_RAW */ - -#if LWIP_UDP -LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB", DMEM_ATTR) -#endif /* LWIP_UDP */ - -#if LWIP_TCP -LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB", DMEM_ATTR) -LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN", DMEM_ATTR) -LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG", DMEM_ATTR) -#endif /* LWIP_TCP */ - -#if IP_REASSEMBLY -LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA", DMEM_ATTR) -#endif /* IP_REASSEMBLY */ -#if IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF -LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF", DMEM_ATTR) -#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ - -#if LWIP_NETCONN -LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF") -LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN") -#endif /* LWIP_NETCONN */ - -#if NO_SYS==0 -LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API") -#if !LWIP_TCPIP_CORE_LOCKING_INPUT -LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT") -#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ -#endif /* NO_SYS==0 */ - -#if ARP_QUEUEING -LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE", DMEM_ATTR) -#endif /* ARP_QUEUEING */ - -#if LWIP_IGMP -LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP", DMEM_ATTR) -#endif /* LWIP_IGMP */ - -#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */ -LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT", DMEM_ATTR) -#endif /* LWIP_TIMERS */ - -#if LWIP_SNMP -LWIP_MEMPOOL(SNMP_ROOTNODE, MEMP_NUM_SNMP_ROOTNODE, sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE") -LWIP_MEMPOOL(SNMP_NODE, MEMP_NUM_SNMP_NODE, sizeof(struct mib_list_node), "SNMP_NODE") -LWIP_MEMPOOL(SNMP_VARBIND, MEMP_NUM_SNMP_VARBIND, sizeof(struct snmp_varbind), "SNMP_VARBIND") -LWIP_MEMPOOL(SNMP_VALUE, MEMP_NUM_SNMP_VALUE, SNMP_MAX_VALUE_SIZE, "SNMP_VALUE") -#endif /* LWIP_SNMP */ -#if LWIP_DNS && LWIP_SOCKET -LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB") -#endif /* LWIP_DNS && LWIP_SOCKET */ -#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC -LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST") -#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ -#if PPP_SUPPORT && PPPOE_SUPPORT -LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF") -#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ - -/* - * A list of pools of pbuf's used by LWIP. - * - * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description) - * creates a pool name MEMP_pool_name. description is used in stats.c - * This allocates enough space for the pbuf struct and a payload. - * (Example: pbuf_payload_size=0 allocates only size for the struct) - */ -LWIP_PBUF_MEMPOOL(PBUF, MEMP_NUM_PBUF, 0, "PBUF_REF/ROM", DMEM_ATTR) - -/* XXX: need to align to 4 byte as memp strcut is 4-byte long. otherwise will crash */ -#define LWIP_MEM_ALIGN4_SIZE(size) (((size) + 4 - 1) & ~(4-1)) - -LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, LWIP_MEM_ALIGN4_SIZE(PBUF_POOL_BUFSIZE), "PBUF_POOL", DMEM_ATTR) - - -/* - * Allow for user-defined pools; this must be explicitly set in lwipopts.h - * since the default is to NOT look for lwippools.h - */ -#if MEMP_USE_CUSTOM_POOLS -#include "lwippools.h" -#endif /* MEMP_USE_CUSTOM_POOLS */ - -/* - * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later - * (#undef is ignored for something that is not defined) - */ -#undef LWIP_MEMPOOL -#undef LWIP_MALLOC_MEMPOOL -#undef LWIP_MALLOC_MEMPOOL_START -#undef LWIP_MALLOC_MEMPOOL_END -#undef LWIP_PBUF_MEMPOOL diff --git a/tools/sdk/lwip/include/lwip/netbuf.h b/tools/sdk/lwip/include/lwip/netbuf.h deleted file mode 100644 index b554a579d..000000000 --- a/tools/sdk/lwip/include/lwip/netbuf.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_NETBUF_H__ -#define __LWIP_NETBUF_H__ - -#include "lwip/opt.h" -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** This netbuf has dest-addr/port set */ -#define NETBUF_FLAG_DESTADDR 0x01 -/** This netbuf includes a checksum */ -#define NETBUF_FLAG_CHKSUM 0x02 - -struct netbuf { - struct pbuf *p, *ptr; - ip_addr_t addr; - u16_t port; -#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY -#if LWIP_CHECKSUM_ON_COPY - u8_t flags; -#endif /* LWIP_CHECKSUM_ON_COPY */ - u16_t toport_chksum; -#if LWIP_NETBUF_RECVINFO - ip_addr_t toaddr; -#endif /* LWIP_NETBUF_RECVINFO */ -#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ -}; - -/* Network buffer functions: */ -struct netbuf * netbuf_new (void)ICACHE_FLASH_ATTR; -void netbuf_delete (struct netbuf *buf)ICACHE_FLASH_ATTR; -void * netbuf_alloc (struct netbuf *buf, u16_t size)ICACHE_FLASH_ATTR; -void netbuf_free (struct netbuf *buf)ICACHE_FLASH_ATTR; -err_t netbuf_ref (struct netbuf *buf, - const void *dataptr, u16_t size)ICACHE_FLASH_ATTR; -void netbuf_chain (struct netbuf *head, - struct netbuf *tail)ICACHE_FLASH_ATTR; - -err_t netbuf_data (struct netbuf *buf, - void **dataptr, u16_t *len)ICACHE_FLASH_ATTR; -s8_t netbuf_next (struct netbuf *buf)ICACHE_FLASH_ATTR; -void netbuf_first (struct netbuf *buf)ICACHE_FLASH_ATTR; - - -#define netbuf_copy_partial(buf, dataptr, len, offset) \ - pbuf_copy_partial((buf)->p, (dataptr), (len), (offset)) -#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) -#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) -#define netbuf_len(buf) ((buf)->p->tot_len) -#define netbuf_fromaddr(buf) (&((buf)->addr)) -#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr), fromaddr) -#define netbuf_fromport(buf) ((buf)->port) -#if LWIP_NETBUF_RECVINFO -#define netbuf_destaddr(buf) (&((buf)->toaddr)) -#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->addr), destaddr) -#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0) -#endif /* LWIP_NETBUF_RECVINFO */ -#if LWIP_CHECKSUM_ON_COPY -#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \ - (buf)->toport_chksum = chksum; } while(0) -#endif /* LWIP_CHECKSUM_ON_COPY */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_NETBUF_H__ */ diff --git a/tools/sdk/lwip/include/lwip/netdb.h b/tools/sdk/lwip/include/lwip/netdb.h deleted file mode 100644 index 7587e2f2d..000000000 --- a/tools/sdk/lwip/include/lwip/netdb.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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 - * - */ -#ifndef __LWIP_NETDB_H__ -#define __LWIP_NETDB_H__ - -#include "lwip/opt.h" - -#if LWIP_DNS && LWIP_SOCKET - -#include /* for size_t */ - -#include "lwip/inet.h" -#include "lwip/sockets.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* some rarely used options */ -#ifndef LWIP_DNS_API_DECLARE_H_ERRNO -#define LWIP_DNS_API_DECLARE_H_ERRNO 1 -#endif - -#ifndef LWIP_DNS_API_DEFINE_ERRORS -#define LWIP_DNS_API_DEFINE_ERRORS 1 -#endif - -#ifndef LWIP_DNS_API_DECLARE_STRUCTS -#define LWIP_DNS_API_DECLARE_STRUCTS 1 -#endif - -#if LWIP_DNS_API_DEFINE_ERRORS -/** Errors used by the DNS API functions, h_errno can be one of them */ -#define EAI_NONAME 200 -#define EAI_SERVICE 201 -#define EAI_FAIL 202 -#define EAI_MEMORY 203 - -#define HOST_NOT_FOUND 210 -#define NO_DATA 211 -#define NO_RECOVERY 212 -#define TRY_AGAIN 213 -#endif /* LWIP_DNS_API_DEFINE_ERRORS */ - -#if LWIP_DNS_API_DECLARE_STRUCTS -struct hostent { - char *h_name; /* Official name of the host. */ - char **h_aliases; /* A pointer to an array of pointers to alternative host names, - terminated by a null pointer. */ - int h_addrtype; /* Address type. */ - int h_length; /* The length, in bytes, of the address. */ - char **h_addr_list; /* A pointer to an array of pointers to network addresses (in - network byte order) for the host, terminated by a null pointer. */ -#define h_addr h_addr_list[0] /* for backward compatibility */ -}; - -struct addrinfo { - int ai_flags; /* Input flags. */ - int ai_family; /* Address family of socket. */ - int ai_socktype; /* Socket type. */ - int ai_protocol; /* Protocol of socket. */ - socklen_t ai_addrlen; /* Length of socket address. */ - struct sockaddr *ai_addr; /* Socket address of socket. */ - char *ai_canonname; /* Canonical name of service location. */ - struct addrinfo *ai_next; /* Pointer to next in list. */ -}; -#endif /* LWIP_DNS_API_DECLARE_STRUCTS */ - -#if LWIP_DNS_API_DECLARE_H_ERRNO -/* application accessable error code set by the DNS API functions */ -extern int h_errno; -#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ - -struct hostent *lwip_gethostbyname(const char *name); -int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, - size_t buflen, struct hostent **result, int *h_errnop); -void lwip_freeaddrinfo(struct addrinfo *ai); -int lwip_getaddrinfo(const char *nodename, - const char *servname, - const struct addrinfo *hints, - struct addrinfo **res); - -#if LWIP_COMPAT_SOCKETS -#define gethostbyname(name) lwip_gethostbyname(name) -#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ - lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) -#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo) -#define getaddrinfo(nodname, servname, hints, res) \ - lwip_getaddrinfo(nodname, servname, hints, res) -#endif /* LWIP_COMPAT_SOCKETS */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_DNS && LWIP_SOCKET */ - -#endif /* __LWIP_NETDB_H__ */ diff --git a/tools/sdk/lwip/include/lwip/netif.h b/tools/sdk/lwip/include/lwip/netif.h deleted file mode 100644 index 04e4f7a0a..000000000 --- a/tools/sdk/lwip/include/lwip/netif.h +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_NETIF_H__ -#define __LWIP_NETIF_H__ - -#include "lwip/opt.h" - -#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) - -#include "lwip/err.h" - -#include "lwip/ip_addr.h" - -#include "lwip/def.h" -#include "lwip/pbuf.h" -#if LWIP_DHCP -struct dhcp; -#endif -#if LWIP_AUTOIP -struct autoip; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Throughout this file, IP addresses are expected to be in - * the same byte order as in IP_PCB. */ - -/** must be the maximum of all used hardware address lengths - across all types of interfaces in use */ -#define NETIF_MAX_HWADDR_LEN 6U - -/** Whether the network interface is 'up'. This is - * a software flag used to control whether this network - * interface is enabled and processes traffic. - * It is set by the startup code (for static IP configuration) or - * by dhcp/autoip when an address has been assigned. - */ -#define NETIF_FLAG_UP 0x01U -/** If set, the netif has broadcast capability. - * Set by the netif driver in its init function. */ -#define NETIF_FLAG_BROADCAST 0x02U -/** If set, the netif is one end of a point-to-point connection. - * Set by the netif driver in its init function. */ -#define NETIF_FLAG_POINTTOPOINT 0x04U -/** If set, the interface is configured using DHCP. - * Set by the DHCP code when starting or stopping DHCP. */ -#define NETIF_FLAG_DHCP 0x08U -/** If set, the interface has an active link - * (set by the network interface driver). - * Either set by the netif driver in its init function (if the link - * is up at that time) or at a later point once the link comes up - * (if link detection is supported by the hardware). */ -#define NETIF_FLAG_LINK_UP 0x10U -/** If set, the netif is an ethernet device using ARP. - * Set by the netif driver in its init function. - * Used to check input packet types and use of DHCP. */ -#define NETIF_FLAG_ETHARP 0x20U -/** If set, the netif is an ethernet device. It might not use - * ARP or TCP/IP if it is used for PPPoE only. - */ -#define NETIF_FLAG_ETHERNET 0x40U -/** If set, the netif has IGMP capability. - * Set by the netif driver in its init function. */ -#define NETIF_FLAG_IGMP 0x80U - -/** Function prototype for netif init functions. Set up flags and output/linkoutput - * callback functions in this function. - * - * @param netif The netif to initialize - */ -typedef err_t (*netif_init_fn)(struct netif *netif); -/** Function prototype for netif->input functions. This function is saved as 'input' - * callback function in the netif struct. Call it when a packet has been received. - * - * @param p The received packet, copied into a pbuf - * @param inp The netif which received the packet - */ -typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp); -/** Function prototype for netif->output functions. Called by lwIP when a packet - * shall be sent. For ethernet netif, set this to 'etharp_output' and set - * 'linkoutput'. - * - * @param netif The netif which shall send a packet - * @param p The packet to send (p->payload points to IP header) - * @param ipaddr The IP address to which the packet shall be sent - */ -typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p, - ip_addr_t *ipaddr); -/** Function prototype for netif->linkoutput functions. Only used for ethernet - * netifs. This function is called by ARP when a packet shall be sent. - * - * @param netif The netif which shall send a packet - * @param p The packet to send (raw ethernet packet) - */ -typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p); -/** Function prototype for netif status- or link-callback functions. */ -typedef void (*netif_status_callback_fn)(struct netif *netif); -/** Function prototype for netif igmp_mac_filter functions */ -typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif, - ip_addr_t *group, u8_t action); - -/*add DHCP event processing by LiuHan*/ -typedef void (*dhcp_event_fn)(void); - -/** Generic data structure used for all lwIP network interfaces. - * The following fields should be filled in by the initialization - * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ -struct netif { - /** pointer to next in linked list */ - struct netif *next; - - /** IP address configuration in network byte order */ - ip_addr_t ip_addr; - ip_addr_t netmask; - ip_addr_t gw; - - /** This function is called by the network device driver - * to pass a packet up the TCP/IP stack. ÏòIP²ãÊäÈëÊý¾Ý°ü*/ - netif_input_fn input; - /** This function is called by the IP module when it wants - * to send a packet on the interface. This function typically - * first resolves the hardware address, then sends the packet. ·¢ËÍIPÊý¾Ý°ü*/ - netif_output_fn output; - /** This function is called by the ARP module when it wants - * to send a packet on the interface. This function outputs - * the pbuf as-is on the link medium. µ×²ãÊý¾Ý°ü·¢ËÍ*/ - netif_linkoutput_fn linkoutput; -#if LWIP_NETIF_STATUS_CALLBACK - /** This function is called when the netif state is set to up or down - */ - netif_status_callback_fn status_callback; -#endif /* LWIP_NETIF_STATUS_CALLBACK */ -#if LWIP_NETIF_LINK_CALLBACK - /** This function is called when the netif link is set to up or down - */ - netif_status_callback_fn link_callback; -#endif /* LWIP_NETIF_LINK_CALLBACK */ - /** This field can be set by the device driver and could point - * to state information for the device. ×ÔÓÉÉèÖÃ×ֶΣ¬±ÈÈçÖ¸Ïòµ×²ãÉ豸Ïà¹ØÐÅÏ¢*/ - void *state; -#if LWIP_DHCP - /** the DHCP client state information for this netif */ - struct dhcp *dhcp; - struct udp_pcb *dhcps_pcb; //dhcps - dhcp_event_fn dhcp_event; -#endif /* LWIP_DHCP */ -#if LWIP_AUTOIP - /** the AutoIP client state information for this netif */ - struct autoip *autoip; -#endif -#if LWIP_NETIF_HOSTNAME - /* the hostname for this netif, NULL is a valid value */ - char* hostname; -#endif /* LWIP_NETIF_HOSTNAME */ - /** maximum transfer unit (in bytes) ¸Ã½Ó¿ÚÔÊÐíµÄ×î´óÊý¾Ý°ü³¤¶È£¬¶àÊÇ1500*/ - u16_t mtu; - /** number of bytes used in hwaddr¸Ã½Ó¿ÚÎïÀíµØÖ·³¤¶È */ - u8_t hwaddr_len; - /** link level hardware address of this interface ¸Ã½Ó¿ÚÎïÀíµØÖ·*/ - u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; - /** flags (see NETIF_FLAG_ above) ¸Ã½Ó¿Ú״̬¡¢ÊôÐÔ×Ö¶Î*/ - u8_t flags; - /** descriptive abbreviation ¸Ã½Ó¿ÚµÄÃû×Ö*/ - char name[2]; - /** number of this interface ¸Ã½Ó¿ÚµÄ±àºÅ*/ - u8_t num; -#if LWIP_SNMP - /** link type (from "snmp_ifType" enum from snmp.h) */ - u8_t link_type; - /** (estimate) link speed */ - u32_t link_speed; - /** timestamp at last change made (up/down) */ - u32_t ts; - /** counters */ - u32_t ifinoctets; - u32_t ifinucastpkts; - u32_t ifinnucastpkts; - u32_t ifindiscards; - u32_t ifoutoctets; - u32_t ifoutucastpkts; - u32_t ifoutnucastpkts; - u32_t ifoutdiscards; -#endif /* LWIP_SNMP */ -#if LWIP_IGMP - /** This function could be called to add or delete a entry in the multicast - filter table of the ethernet MAC.*/ - netif_igmp_mac_filter_fn igmp_mac_filter; -#endif /* LWIP_IGMP */ -#if LWIP_NETIF_HWADDRHINT - u8_t *addr_hint; -#endif /* LWIP_NETIF_HWADDRHINT */ -#if ENABLE_LOOPBACK - /* List of packets to be queued for ourselves. Ö¸Ïò·¢Ë͸ø×Ô¼ºµÄÊý¾Ý°üµÄpbuf*/ - struct pbuf *loop_first;//µÚÒ»¸ö - struct pbuf *loop_last;//×îºóÒ»¸ö -#if LWIP_LOOPBACK_MAX_PBUFS - u16_t loop_cnt_current; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ -#endif /* ENABLE_LOOPBACK */ -}; - -#if LWIP_SNMP -#define NETIF_INIT_SNMP(netif, type, speed) \ - /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \ - (netif)->link_type = (type); \ - /* your link speed here (units: bits per second) */ \ - (netif)->link_speed = (speed); \ - (netif)->ts = 0; \ - (netif)->ifinoctets = 0; \ - (netif)->ifinucastpkts = 0; \ - (netif)->ifinnucastpkts = 0; \ - (netif)->ifindiscards = 0; \ - (netif)->ifoutoctets = 0; \ - (netif)->ifoutucastpkts = 0; \ - (netif)->ifoutnucastpkts = 0; \ - (netif)->ifoutdiscards = 0 -#else /* LWIP_SNMP */ -#define NETIF_INIT_SNMP(netif, type, speed) -#endif /* LWIP_SNMP */ - - -/** The list of network interfaces. */ -extern struct netif *netif_list; -/** The default network interface. */ -extern struct netif *netif_default; - -void netif_init(void)ICACHE_FLASH_ATTR; - -struct netif *netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, - ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)ICACHE_FLASH_ATTR; - -void -netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, - ip_addr_t *gw)ICACHE_FLASH_ATTR; -void netif_remove(struct netif * netif)ICACHE_FLASH_ATTR; - -/* Returns a network interface given its name. The name is of the form - "et0", where the first two letters are the "name" field in the - netif structure, and the digit is in the num field in the same - structure. */ -struct netif *netif_find(char *name)ICACHE_FLASH_ATTR; - -void netif_set_default(struct netif *netif)ICACHE_FLASH_ATTR; - -void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; -void netif_set_netmask(struct netif *netif, ip_addr_t *netmask)ICACHE_FLASH_ATTR; -void netif_set_gw(struct netif *netif, ip_addr_t *gw)ICACHE_FLASH_ATTR; - -void netif_set_up(struct netif *netif)ICACHE_FLASH_ATTR; -void netif_set_down(struct netif *netif)ICACHE_FLASH_ATTR; -/** Ask if an interface is up */ -#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0) - -#if LWIP_NETIF_STATUS_CALLBACK -void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)ICACHE_FLASH_ATTR; -#endif /* LWIP_NETIF_STATUS_CALLBACK */ - -void netif_set_link_up(struct netif *netif)ICACHE_FLASH_ATTR; -void netif_set_link_down(struct netif *netif)ICACHE_FLASH_ATTR; -/** Ask if a link is up */ -#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0) - -#if LWIP_NETIF_LINK_CALLBACK -void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)ICACHE_FLASH_ATTR; -#endif /* LWIP_NETIF_LINK_CALLBACK */ - -#if LWIP_NETIF_HOSTNAME -#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0) -#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL) -#endif /* LWIP_NETIF_HOSTNAME */ - -#if LWIP_IGMP -#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0) -#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL) -#endif /* LWIP_IGMP */ - -#if ENABLE_LOOPBACK -err_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *dest_ip)ICACHE_FLASH_ATTR; -void netif_poll(struct netif *netif)ICACHE_FLASH_ATTR; -#if !LWIP_NETIF_LOOPBACK_MULTITHREADING -void netif_poll_all(void)ICACHE_FLASH_ATTR; -#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ -#endif /* ENABLE_LOOPBACK */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_NETIF_H__ */ diff --git a/tools/sdk/lwip/include/lwip/netifapi.h b/tools/sdk/lwip/include/lwip/netifapi.h deleted file mode 100644 index 33318efaf..000000000 --- a/tools/sdk/lwip/include/lwip/netifapi.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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. - * - */ - -#ifndef __LWIP_NETIFAPI_H__ -#define __LWIP_NETIFAPI_H__ - -#include "lwip/opt.h" - -#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/sys.h" -#include "lwip/netif.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*netifapi_void_fn)(struct netif *netif); -typedef err_t (*netifapi_errt_fn)(struct netif *netif); - -struct netifapi_msg_msg { -#if !LWIP_TCPIP_CORE_LOCKING - sys_sem_t sem; -#endif /* !LWIP_TCPIP_CORE_LOCKING */ - err_t err; - struct netif *netif; - union { - struct { - ip_addr_t *ipaddr; - ip_addr_t *netmask; - ip_addr_t *gw; - void *state; - netif_init_fn init; - netif_input_fn input; - } add; - struct { - netifapi_void_fn voidfunc; - netifapi_errt_fn errtfunc; - } common; - } msg; -}; - -struct netifapi_msg { - void (* function)(struct netifapi_msg_msg *msg); - struct netifapi_msg_msg msg; -}; - - -/* API for application */ -err_t netifapi_netif_add ( struct netif *netif, - ip_addr_t *ipaddr, - ip_addr_t *netmask, - ip_addr_t *gw, - void *state, - netif_init_fn init, - netif_input_fn input); - -err_t netifapi_netif_set_addr ( struct netif *netif, - ip_addr_t *ipaddr, - ip_addr_t *netmask, - ip_addr_t *gw ); - -err_t netifapi_netif_common ( struct netif *netif, - netifapi_void_fn voidfunc, - netifapi_errt_fn errtfunc); - -#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) -#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) -#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL) -#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) -#define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start) -#define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL) -#define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start) -#define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_NETIF_API */ - -#endif /* __LWIP_NETIFAPI_H__ */ diff --git a/tools/sdk/lwip/include/lwip/opt.h b/tools/sdk/lwip/include/lwip/opt.h deleted file mode 100644 index 0d2b3fcc5..000000000 --- a/tools/sdk/lwip/include/lwip/opt.h +++ /dev/null @@ -1,2043 +0,0 @@ -/** - * @file - * - * lwIP Options Configuration - */ - -/* - * 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 - * - */ -#ifndef __LWIP_OPT_H__ -#define __LWIP_OPT_H__ - -/* - * Include user defined options first. Anything not defined in these files - * will be set to standard values. Override anything you dont like! - */ -#include "lwipopts.h" -#include "lwip/debug.h" - -/* - ----------------------------------------------- - ---------- Platform specific locking ---------- - ----------------------------------------------- -*/ - -/** - * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain - * critical regions during buffer allocation, deallocation and memory - * allocation and deallocation. - */ -#ifndef SYS_LIGHTWEIGHT_PROT -#define SYS_LIGHTWEIGHT_PROT 0 -#endif - -/** - * NO_SYS==1: Provides VERY minimal functionality. Otherwise, - * use lwIP facilities. - */ -#ifndef NO_SYS -#define NO_SYS 1 -#endif - -/** - * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 - * Mainly for compatibility to old versions. - */ -#ifndef NO_SYS_NO_TIMERS -#define NO_SYS_NO_TIMERS 1 -#endif - -/** - * MEMCPY: override this if you have a faster implementation at hand than the - * one included in your C library - */ -#ifndef MEMCPY -#define MEMCPY(dst,src,len) memcpy(dst,src,len) -#endif - -/** - * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a - * call to memcpy() if the length is known at compile time and is small. - */ -#ifndef SMEMCPY -#define SMEMCPY(dst,src,len) memcpy(dst,src,len) -#endif - -/* - ------------------------------------ - ---------- Memory options ---------- - ------------------------------------ -*/ -/** - * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library - * instead of the lwip internal allocator. Can save code size if you - * already use it. - */ -#ifndef MEM_LIBC_MALLOC -#define MEM_LIBC_MALLOC 0 -#endif - -/** -* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. -* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution -* speed and usage from interrupts! -*/ -#ifndef MEMP_MEM_MALLOC -#define MEMP_MEM_MALLOC 0 -#endif - -/** - * MEM_ALIGNMENT: should be set to the alignment of the CPU - * 4 byte alignment -> #define MEM_ALIGNMENT 4 - * 2 byte alignment -> #define MEM_ALIGNMENT 2 - */ -#ifndef MEM_ALIGNMENT -#define MEM_ALIGNMENT 1 -#endif - -/** - * MEM_SIZE: the size of the heap memory. If the application will send - * a lot of data that needs to be copied, this should be set high. - */ -#ifndef MEM_SIZE -#define MEM_SIZE 1600 -#endif - -/** - * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array. - * This can be used to individually change the location of each pool. - * Default is one big array for all pools - */ -#ifndef MEMP_SEPARATE_POOLS -#define MEMP_SEPARATE_POOLS 0 -#endif - -/** - * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable - * amount of bytes before and after each memp element in every pool and fills - * it with a prominent default value. - * MEMP_OVERFLOW_CHECK == 0 no checking - * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed - * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time - * memp_malloc() or memp_free() is called (useful but slow!) - */ -#ifndef MEMP_OVERFLOW_CHECK -#define MEMP_OVERFLOW_CHECK 0 -#endif - -/** - * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make - * sure that there are no cycles in the linked lists. - */ -#ifndef MEMP_SANITY_CHECK -#define MEMP_SANITY_CHECK 0 -#endif - -/** - * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set - * of memory pools of various sizes. When mem_malloc is called, an element of - * the smallest pool that can provide the length needed is returned. - * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. - */ -#ifndef MEM_USE_POOLS -#define MEM_USE_POOLS 0 -#endif - -/** - * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next - * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more - * reliable. */ -#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL -#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 -#endif - -/** - * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h - * that defines additional pools beyond the "standard" ones required - * by lwIP. If you set this to 1, you must have lwippools.h in your - * inlude path somewhere. - */ -#ifndef MEMP_USE_CUSTOM_POOLS -#define MEMP_USE_CUSTOM_POOLS 0 -#endif - -/** - * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from - * interrupt context (or another context that doesn't allow waiting for a - * semaphore). - * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, - * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs - * with each loop so that mem_free can run. - * - * ATTENTION: As you can see from the above description, this leads to dis-/ - * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc - * can need longer. - * - * If you don't want that, at least for NO_SYS=0, you can still use the following - * functions to enqueue a deallocation call which then runs in the tcpip_thread - * context: - * - pbuf_free_callback(p); - * - mem_free_callback(m); - */ -#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT -#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 -#endif - -/* - ------------------------------------------------ - ---------- Internal Memory Pool Sizes ---------- - ------------------------------------------------ -*/ -/** - * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). - * If the application sends a lot of data out of ROM (or other static memory), - * this should be set high. - */ -#ifndef MEMP_NUM_PBUF -#define MEMP_NUM_PBUF 16 -#endif - -/** - * MEMP_NUM_RAW_PCB: Number of raw connection PCBs - * (requires the LWIP_RAW option) - */ -#ifndef MEMP_NUM_RAW_PCB -#define MEMP_NUM_RAW_PCB 4 -#endif - -/** - * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One - * per active UDP "connection". - * (requires the LWIP_UDP option) - */ -#ifndef MEMP_NUM_UDP_PCB -#define MEMP_NUM_UDP_PCB 4 -#endif - -/** - * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. - * (requires the LWIP_TCP option) - */ -#ifndef MEMP_NUM_TCP_PCB -#define MEMP_NUM_TCP_PCB 5 -#endif - -/** - * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. - * (requires the LWIP_TCP option) - */ -#ifndef MEMP_NUM_TCP_PCB_LISTEN -#define MEMP_NUM_TCP_PCB_LISTEN 8 -#endif - -/** - * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. - * (requires the LWIP_TCP option) - */ -#ifndef MEMP_NUM_TCP_SEG -#define MEMP_NUM_TCP_SEG 16 -#endif - -/** - * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for - * reassembly (whole packets, not fragments!) - */ -#ifndef MEMP_NUM_REASSDATA -#define MEMP_NUM_REASSDATA 5 -#endif - -/** - * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent - * (fragments, not whole packets!). - * This is only used with IP_FRAG_USES_STATIC_BUF==0 and - * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs - * where the packet is not yet sent when netif->output returns. - */ -#ifndef MEMP_NUM_FRAG_PBUF -#define MEMP_NUM_FRAG_PBUF 15 -#endif - -/** - * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing - * packets (pbufs) that are waiting for an ARP request (to resolve - * their destination address) to finish. - * (requires the ARP_QUEUEING option) - */ -#ifndef MEMP_NUM_ARP_QUEUE -#define MEMP_NUM_ARP_QUEUE 30 -#endif - -/** - * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces - * can be members et the same time (one per netif - allsystems group -, plus one - * per netif membership). - * (requires the LWIP_IGMP option) - */ -#ifndef MEMP_NUM_IGMP_GROUP -#define MEMP_NUM_IGMP_GROUP 8 -#endif - -/** - * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. - * (requires NO_SYS==0) - */ -#ifndef MEMP_NUM_SYS_TIMEOUT -#define MEMP_NUM_SYS_TIMEOUT 3 -#endif - -/** - * MEMP_NUM_NETBUF: the number of struct netbufs. - * (only needed if you use the sequential API, like api_lib.c) - */ -#ifndef MEMP_NUM_NETBUF -#define MEMP_NUM_NETBUF 2 -#endif - -/** - * MEMP_NUM_NETCONN: the number of struct netconns. - * (only needed if you use the sequential API, like api_lib.c) - */ -#ifndef MEMP_NUM_NETCONN -#define MEMP_NUM_NETCONN 4 -#endif - -/** - * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used - * for callback/timeout API communication. - * (only needed if you use tcpip.c) - */ -#ifndef MEMP_NUM_TCPIP_MSG_API -#define MEMP_NUM_TCPIP_MSG_API 8 -#endif - -/** - * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used - * for incoming packets. - * (only needed if you use tcpip.c) - */ -#ifndef MEMP_NUM_TCPIP_MSG_INPKT -#define MEMP_NUM_TCPIP_MSG_INPKT 8 -#endif - -/** - * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree. - */ -#ifndef MEMP_NUM_SNMP_NODE -#define MEMP_NUM_SNMP_NODE 50 -#endif - -/** - * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree. - * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least! - */ -#ifndef MEMP_NUM_SNMP_ROOTNODE -#define MEMP_NUM_SNMP_ROOTNODE 30 -#endif - -/** - * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to - * be changed normally) - 2 of these are used per request (1 for input, - * 1 for output) - */ -#ifndef MEMP_NUM_SNMP_VARBIND -#define MEMP_NUM_SNMP_VARBIND 2 -#endif - -/** - * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used - * (does not have to be changed normally) - 3 of these are used per request - * (1 for the value read and 2 for OIDs - input and output) - */ -#ifndef MEMP_NUM_SNMP_VALUE -#define MEMP_NUM_SNMP_VALUE 3 -#endif - -/** - * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls - * (before freeing the corresponding memory using lwip_freeaddrinfo()). - */ -#ifndef MEMP_NUM_NETDB -#define MEMP_NUM_NETDB 1 -#endif - -/** - * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list - * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. - */ -#ifndef MEMP_NUM_LOCALHOSTLIST -#define MEMP_NUM_LOCALHOSTLIST 1 -#endif - -/** - * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE - * interfaces (only used with PPPOE_SUPPORT==1) - */ -#ifndef MEMP_NUM_PPPOE_INTERFACES -#define MEMP_NUM_PPPOE_INTERFACES 1 -#endif - -/** - * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. - */ -#ifndef PBUF_POOL_SIZE -#define PBUF_POOL_SIZE 16 -#endif - -/* - --------------------------------- - ---------- ARP options ---------- - --------------------------------- -*/ -/** - * LWIP_ARP==1: Enable ARP functionality. - */ -#ifndef LWIP_ARP -#define LWIP_ARP 1 -#endif - -/** - * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. - */ -#ifndef ARP_TABLE_SIZE -#define ARP_TABLE_SIZE 10 -#endif - -/** - * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address - * resolution. By default, only the most recent packet is queued per IP address. - * This is sufficient for most protocols and mainly reduces TCP connection - * startup time. Set this to 1 if you know your application sends more than one - * packet in a row to an IP address that is not in the ARP cache. - */ -#ifndef ARP_QUEUEING -#define ARP_QUEUEING 0 -#endif - -/** - * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be - * updated with the source MAC and IP addresses supplied in the packet. - * You may want to disable this if you do not trust LAN peers to have the - * correct addresses, or as a limited approach to attempt to handle - * spoofing. If disabled, lwIP will need to make a new ARP request if - * the peer is not already in the ARP table, adding a little latency. - * The peer *is* in the ARP table if it requested our address before. - * Also notice that this slows down input processing of every IP packet! - */ -#ifndef ETHARP_TRUST_IP_MAC -#define ETHARP_TRUST_IP_MAC 0 -#endif - -/** - * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header. - * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. - * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. - * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. - */ -#ifndef ETHARP_SUPPORT_VLAN -#define ETHARP_SUPPORT_VLAN 0 -#endif - -/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP - * might be disabled - */ -#ifndef LWIP_ETHERNET -#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT) -#endif - -/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure - * alignment of payload after that header. Since the header is 14 bytes long, - * without this padding e.g. addresses in the IP header will not be aligned - * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. - */ -#ifndef ETH_PAD_SIZE -#define ETH_PAD_SIZE 0 -#endif - -/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table - * entries (using etharp_add_static_entry/etharp_remove_static_entry). - */ -#ifndef ETHARP_SUPPORT_STATIC_ENTRIES -#define ETHARP_SUPPORT_STATIC_ENTRIES 0 -#endif - - -/* - -------------------------------- - ---------- IP options ---------- - -------------------------------- -*/ -/** - * IP_FORWARD==1: Enables the ability to forward IP packets across network - * interfaces. If you are going to run lwIP on a device with only one network - * interface, define this to 0. - */ -#ifndef IP_FORWARD -#define IP_FORWARD 0 -#endif - -/** - * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. - * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. - * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). - */ -#ifndef IP_OPTIONS_ALLOWED -#define IP_OPTIONS_ALLOWED 1 -#endif - -/** - * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that - * this option does not affect outgoing packet sizes, which can be controlled - * via IP_FRAG. - */ -#ifndef IP_REASSEMBLY -#define IP_REASSEMBLY 0 -#endif - -/** - * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note - * that this option does not affect incoming packet sizes, which can be - * controlled via IP_REASSEMBLY. - */ -#ifndef IP_FRAG -#define IP_FRAG 1 -#endif - -/** - * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) - * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived - * in this time, the whole packet is discarded. - */ -#ifndef IP_REASS_MAXAGE -#define IP_REASS_MAXAGE 3 -#endif - -/** - * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. - * Since the received pbufs are enqueued, be sure to configure - * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive - * packets even if the maximum amount of fragments is enqueued for reassembly! - */ -#ifndef IP_REASS_MAX_PBUFS -#define IP_REASS_MAX_PBUFS 10 -#endif - -/** - * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP - * fragmentation. Otherwise pbufs are allocated and reference the original - * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1, - * new PBUF_RAM pbufs are used for fragments). - * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs! - */ -#ifndef IP_FRAG_USES_STATIC_BUF -#define IP_FRAG_USES_STATIC_BUF 0 -#endif - -/** - * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer - * (requires IP_FRAG_USES_STATIC_BUF==1) - */ -#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) -#define IP_FRAG_MAX_MTU 1500 -#endif - -/** - * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. - */ -#ifndef IP_DEFAULT_TTL -#define IP_DEFAULT_TTL 255 -#endif - -/** - * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast - * filter per pcb on udp and raw send operations. To enable broadcast filter - * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. - */ -#ifndef IP_SOF_BROADCAST -#define IP_SOF_BROADCAST 0 -#endif - -/** - * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast - * filter on recv operations. - */ -#ifndef IP_SOF_BROADCAST_RECV -#define IP_SOF_BROADCAST_RECV 0 -#endif - -/* - ---------------------------------- - ---------- ICMP options ---------- - ---------------------------------- -*/ -/** - * LWIP_ICMP==1: Enable ICMP module inside the IP stack. - * Be careful, disable that make your product non-compliant to RFC1122 - */ -#ifndef LWIP_ICMP -#define LWIP_ICMP 1 -#endif - -/** - * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. - */ -#ifndef ICMP_TTL -#define ICMP_TTL (IP_DEFAULT_TTL) -#endif - -/** - * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) - */ -#ifndef LWIP_BROADCAST_PING -#define LWIP_BROADCAST_PING 0 -#endif - -/** - * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) - */ -#ifndef LWIP_MULTICAST_PING -#define LWIP_MULTICAST_PING 0 -#endif - -/* - --------------------------------- - ---------- RAW options ---------- - --------------------------------- -*/ -/** - * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. - */ -#ifndef LWIP_RAW -#define LWIP_RAW 1 -#endif - -/** - * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. - */ -#ifndef RAW_TTL -#define RAW_TTL (IP_DEFAULT_TTL) -#endif - -/* - ---------------------------------- - ---------- DHCP options ---------- - ---------------------------------- -*/ -/** - * LWIP_DHCP==1: Enable DHCP module. - */ -#ifndef LWIP_DHCP -#define LWIP_DHCP 0 -#endif - -/** - * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. - */ -#ifndef DHCP_DOES_ARP_CHECK -#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) -#endif - -/* - ------------------------------------ - ---------- AUTOIP options ---------- - ------------------------------------ -*/ -/** - * LWIP_AUTOIP==1: Enable AUTOIP module. - */ -#ifndef LWIP_AUTOIP -#define LWIP_AUTOIP 0 -#endif - -/** - * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on - * the same interface at the same time. - */ -#ifndef LWIP_DHCP_AUTOIP_COOP -#define LWIP_DHCP_AUTOIP_COOP 0 -#endif - -/** - * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes - * that should be sent before falling back on AUTOIP. This can be set - * as low as 1 to get an AutoIP address very quickly, but you should - * be prepared to handle a changing IP address when DHCP overrides - * AutoIP. - */ -#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES -#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 -#endif - -/* - ---------------------------------- - ---------- SNMP options ---------- - ---------------------------------- -*/ -/** - * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP - * transport. - */ -#ifndef LWIP_SNMP -#define LWIP_SNMP 0 -#endif - -/** - * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will - * allow. At least one request buffer is required. - * Does not have to be changed unless external MIBs answer request asynchronously - */ -#ifndef SNMP_CONCURRENT_REQUESTS -#define SNMP_CONCURRENT_REQUESTS 1 -#endif - -/** - * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap - * destination is required - */ -#ifndef SNMP_TRAP_DESTINATIONS -#define SNMP_TRAP_DESTINATIONS 1 -#endif - -/** - * SNMP_PRIVATE_MIB: - * When using a private MIB, you have to create a file 'private_mib.h' that contains - * a 'struct mib_array_node mib_private' which contains your MIB. - */ -#ifndef SNMP_PRIVATE_MIB -#define SNMP_PRIVATE_MIB 0 -#endif - -/** - * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not - * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). - * Unsafe requests are disabled by default! - */ -#ifndef SNMP_SAFE_REQUESTS -#define SNMP_SAFE_REQUESTS 1 -#endif - -/** - * The maximum length of strings used. This affects the size of - * MEMP_SNMP_VALUE elements. - */ -#ifndef SNMP_MAX_OCTET_STRING_LEN -#define SNMP_MAX_OCTET_STRING_LEN 127 -#endif - -/** - * The maximum depth of the SNMP tree. - * With private MIBs enabled, this depends on your MIB! - * This affects the size of MEMP_SNMP_VALUE elements. - */ -#ifndef SNMP_MAX_TREE_DEPTH -#define SNMP_MAX_TREE_DEPTH 15 -#endif - -/** - * The size of the MEMP_SNMP_VALUE elements, normally calculated from - * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH. - */ -#ifndef SNMP_MAX_VALUE_SIZE -#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH)) -#endif - -/* - ---------------------------------- - ---------- IGMP options ---------- - ---------------------------------- -*/ -/** - * LWIP_IGMP==1: Turn on IGMP module. - */ -#ifndef LWIP_IGMP -#define LWIP_IGMP 0 -#endif - -/* - ---------------------------------- - ---------- DNS options ----------- - ---------------------------------- -*/ -/** - * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS - * transport. - */ -#ifndef LWIP_DNS -#define LWIP_DNS 0 -#endif - -/** DNS maximum number of entries to maintain locally. */ -#ifndef DNS_TABLE_SIZE -#define DNS_TABLE_SIZE 4 -#endif - -/** DNS maximum host name length supported in the name table. */ -#ifndef DNS_MAX_NAME_LENGTH -#define DNS_MAX_NAME_LENGTH 256 -#endif - -/** The maximum of DNS servers */ -#ifndef DNS_MAX_SERVERS -#define DNS_MAX_SERVERS 2 -#endif - -/** DNS do a name checking between the query and the response. */ -#ifndef DNS_DOES_NAME_CHECK -#define DNS_DOES_NAME_CHECK 1 -#endif - -/** DNS message max. size. Default value is RFC compliant. */ -#ifndef DNS_MSG_SIZE -#define DNS_MSG_SIZE 512 -#endif - -/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, - * you have to define - * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} - * (an array of structs name/address, where address is an u32_t in network - * byte order). - * - * Instead, you can also use an external function: - * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) - * that returns the IP address or INADDR_NONE if not found. - */ -#ifndef DNS_LOCAL_HOSTLIST -#define DNS_LOCAL_HOSTLIST 0 -#endif /* DNS_LOCAL_HOSTLIST */ - -/** If this is turned on, the local host-list can be dynamically changed - * at runtime. */ -#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC -#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - -/* - --------------------------------- - ---------- UDP options ---------- - --------------------------------- -*/ -/** - * LWIP_UDP==1: Turn on UDP. - */ -#ifndef LWIP_UDP -#define LWIP_UDP 1 -#endif - -/** - * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) - */ -#ifndef LWIP_UDPLITE -#define LWIP_UDPLITE 0 -#endif - -/** - * UDP_TTL: Default Time-To-Live value. - */ -#ifndef UDP_TTL -#define UDP_TTL (IP_DEFAULT_TTL) -#endif - -/** - * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. - */ -#ifndef LWIP_NETBUF_RECVINFO -#define LWIP_NETBUF_RECVINFO 0 -#endif - -/* - --------------------------------- - ---------- TCP options ---------- - --------------------------------- -*/ -/** - * LWIP_TCP==1: Turn on TCP. - */ -#ifndef LWIP_TCP -#define LWIP_TCP 1 -#endif - -/** - * TCP_TTL: Default Time-To-Live value. - */ -#ifndef TCP_TTL -#define TCP_TTL (IP_DEFAULT_TTL) -#endif - -/** - * TCP_WND: The size of a TCP window. This must be at least - * (2 * TCP_MSS) for things to work well - */ -#ifndef TCP_WND -#define TCP_WND (4 * TCP_MSS) -#endif - -/** - * TCP_MAXRTX: Maximum number of retransmissions of data segments. - */ -#ifndef TCP_MAXRTX -#define TCP_MAXRTX 12 -#endif - -/** - * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. - */ -#ifndef TCP_SYNMAXRTX -#define TCP_SYNMAXRTX 6 -#endif - -/** - * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. - * Define to 0 if your device is low on memory. - */ -#ifndef TCP_QUEUE_OOSEQ -#define TCP_QUEUE_OOSEQ (LWIP_TCP) -#endif - -/** - * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, - * you might want to increase this.) - * For the receive side, this MSS is advertised to the remote side - * when opening a connection. For the transmit size, this MSS sets - * an upper limit on the MSS advertised by the remote host. - */ -#ifndef TCP_MSS -#define TCP_MSS 536 -#endif - -/** - * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really - * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which - * reflects the available reassembly buffer size at the remote host) and the - * largest size permitted by the IP layer" (RFC 1122) - * Setting this to 1 enables code that checks TCP_MSS against the MTU of the - * netif used for a connection and limits the MSS if it would be too big otherwise. - */ -#ifndef TCP_CALCULATE_EFF_SEND_MSS -#define TCP_CALCULATE_EFF_SEND_MSS 1 -#endif - - -/** - * TCP_SND_BUF: TCP sender buffer space (bytes). - */ -#ifndef TCP_SND_BUF -#define TCP_SND_BUF 256 -#endif - -/** - * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least - * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. - */ -#ifndef TCP_SND_QUEUELEN -#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) -#endif - -/** - * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than - * TCP_SND_BUF. It is the amount of space which must be available in the - * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). - */ -#ifndef TCP_SNDLOWAT -#define TCP_SNDLOWAT ((TCP_SND_BUF)/2) -#endif - -/** - * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater - * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below - * this number, select returns writable (combined with TCP_SNDLOWAT). - */ -#ifndef TCP_SNDQUEUELOWAT -#define TCP_SNDQUEUELOWAT ((TCP_SND_QUEUELEN)/2) -#endif - -/** - * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. - */ -#ifndef TCP_LISTEN_BACKLOG -#define TCP_LISTEN_BACKLOG 0 -#endif - -/** - * The maximum allowed backlog for TCP listen netconns. - * This backlog is used unless another is explicitly specified. - * 0xff is the maximum (u8_t). - */ -#ifndef TCP_DEFAULT_LISTEN_BACKLOG -#define TCP_DEFAULT_LISTEN_BACKLOG 0xff -#endif - -/** - * TCP_OVERSIZE: The maximum number of bytes that tcp_write may - * allocate ahead of time in an attempt to create shorter pbuf chains - * for transmission. The meaningful range is 0 to TCP_MSS. Some - * suggested values are: - * - * 0: Disable oversized allocation. Each tcp_write() allocates a new - pbuf (old behaviour). - * 1: Allocate size-aligned pbufs with minimal excess. Use this if your - * scatter-gather DMA requires aligned fragments. - * 128: Limit the pbuf/memory overhead to 20%. - * TCP_MSS: Try to create unfragmented TCP packets. - * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. - */ -#ifndef TCP_OVERSIZE -#define TCP_OVERSIZE TCP_MSS -#endif - -/** - * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. - */ -#ifndef LWIP_TCP_TIMESTAMPS -#define LWIP_TCP_TIMESTAMPS 0 -#endif - -/** - * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an - * explicit window update - */ -#ifndef TCP_WND_UPDATE_THRESHOLD -#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4) -#endif - -/** - * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. - * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all - * events (accept, sent, etc) that happen in the system. - * LWIP_CALLBACK_API==1: The PCB callback function is called directly - * for the event. - */ -//#ifndef LWIP_EVENT_API -//#define LWIP_EVENT_API 0 -//#define LWIP_CALLBACK_API 1 -//#else -//#define LWIP_EVENT_API 1 -//#define LWIP_CALLBACK_API 0 -//#endif - - -/* - ---------------------------------- - ---------- Pbuf options ---------- - ---------------------------------- -*/ -/** - * PBUF_LINK_HLEN: the number of bytes that should be allocated for a - * link level header. The default is 14, the standard value for - * Ethernet. - */ -#ifndef PBUF_LINK_HLEN -#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) -#endif - -/** - * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is - * designed to accomodate single full size TCP frame in one pbuf, including - * TCP_MSS, IP header, and link header. - */ -#ifndef PBUF_POOL_BUFSIZE -#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) -#endif - -/* - ------------------------------------------------ - ---------- Network Interfaces options ---------- - ------------------------------------------------ -*/ -/** - * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname - * field. - */ -#ifndef LWIP_NETIF_HOSTNAME -#define LWIP_NETIF_HOSTNAME 0 -#endif - -/** - * LWIP_NETIF_API==1: Support netif api (in netifapi.c) - */ -#ifndef LWIP_NETIF_API -#define LWIP_NETIF_API 0 -#endif - -/** - * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface - * changes its up/down status (i.e., due to DHCP IP acquistion) - */ -#ifndef LWIP_NETIF_STATUS_CALLBACK -#define LWIP_NETIF_STATUS_CALLBACK 0 -#endif - -/** - * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface - * whenever the link changes (i.e., link down) - */ -#ifndef LWIP_NETIF_LINK_CALLBACK -#define LWIP_NETIF_LINK_CALLBACK 0 -#endif - -/** - * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table - * indices) in struct netif. TCP and UDP can make use of this to prevent - * scanning the ARP table for every sent packet. While this is faster for big - * ARP tables or many concurrent connections, it might be counterproductive - * if you have a tiny ARP table or if there never are concurrent connections. - */ -#ifndef LWIP_NETIF_HWADDRHINT -#define LWIP_NETIF_HWADDRHINT 0 -#endif - -/** - * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP - * address equal to the netif IP address, looping them back up the stack. - */ -#ifndef LWIP_NETIF_LOOPBACK -#define LWIP_NETIF_LOOPBACK 1 -#endif - -/** - * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback - * sending for each netif (0 = disabled) - */ -#ifndef LWIP_LOOPBACK_MAX_PBUFS -#define LWIP_LOOPBACK_MAX_PBUFS 0 -#endif - -/** - * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in - * the system, as netifs must change how they behave depending on this setting - * for the LWIP_NETIF_LOOPBACK option to work. - * Setting this is needed to avoid reentering non-reentrant functions like - * tcp_input(). - * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a - * multithreaded environment like tcpip.c. In this case, netif->input() - * is called directly. - * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. - * The packets are put on a list and netif_poll() must be called in - * the main application loop. - */ -#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING -#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) -#endif - -/** - * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data - * to be sent into one single pbuf. This is for compatibility with DMA-enabled - * MACs that do not support scatter-gather. - * Beware that this might involve CPU-memcpy before transmitting that would not - * be needed without this flag! Use this only if you need to! - * - * @todo: TCP and IP-frag do not work with this, yet: - */ -#ifndef LWIP_NETIF_TX_SINGLE_PBUF -#define LWIP_NETIF_TX_SINGLE_PBUF 0 -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - -/* - ------------------------------------ - ---------- LOOPIF options ---------- - ------------------------------------ -*/ -/** - * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c - */ -#ifndef LWIP_HAVE_LOOPIF -#define LWIP_HAVE_LOOPIF 1 -#endif - -/* - ------------------------------------ - ---------- SLIPIF options ---------- - ------------------------------------ -*/ -/** - * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c - */ -#ifndef LWIP_HAVE_SLIPIF -#define LWIP_HAVE_SLIPIF 0 -#endif - -/* - ------------------------------------ - ---------- Thread options ---------- - ------------------------------------ -*/ -/** - * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. - */ -#ifndef TCPIP_THREAD_NAME -#define TCPIP_THREAD_NAME "tcpip_thread" -#endif - -/** - * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. - * The stack size value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef TCPIP_THREAD_STACKSIZE -#define TCPIP_THREAD_STACKSIZE 0 -#endif - -/** - * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. - * The priority value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef TCPIP_THREAD_PRIO -#define TCPIP_THREAD_PRIO 1 -#endif - -/** - * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages - * The queue size value itself is platform-dependent, but is passed to - * sys_mbox_new() when tcpip_init is called. - */ -#ifndef TCPIP_MBOX_SIZE -#define TCPIP_MBOX_SIZE 0 -#endif - -/** - * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. - */ -#ifndef SLIPIF_THREAD_NAME -#define SLIPIF_THREAD_NAME "slipif_loop" -#endif - -/** - * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. - * The stack size value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef SLIPIF_THREAD_STACKSIZE -#define SLIPIF_THREAD_STACKSIZE 0 -#endif - -/** - * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. - * The priority value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef SLIPIF_THREAD_PRIO -#define SLIPIF_THREAD_PRIO 1 -#endif - -/** - * PPP_THREAD_NAME: The name assigned to the pppInputThread. - */ -#ifndef PPP_THREAD_NAME -#define PPP_THREAD_NAME "pppInputThread" -#endif - -/** - * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread. - * The stack size value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef PPP_THREAD_STACKSIZE -#define PPP_THREAD_STACKSIZE 0 -#endif - -/** - * PPP_THREAD_PRIO: The priority assigned to the pppInputThread. - * The priority value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef PPP_THREAD_PRIO -#define PPP_THREAD_PRIO 1 -#endif - -/** - * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. - */ -#ifndef DEFAULT_THREAD_NAME -#define DEFAULT_THREAD_NAME "lwIP" -#endif - -/** - * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. - * The stack size value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef DEFAULT_THREAD_STACKSIZE -#define DEFAULT_THREAD_STACKSIZE 0 -#endif - -/** - * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. - * The priority value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef DEFAULT_THREAD_PRIO -#define DEFAULT_THREAD_PRIO 1 -#endif - -/** - * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a - * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed - * to sys_mbox_new() when the recvmbox is created. - */ -#ifndef DEFAULT_RAW_RECVMBOX_SIZE -#define DEFAULT_RAW_RECVMBOX_SIZE 0 -#endif - -/** - * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a - * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed - * to sys_mbox_new() when the recvmbox is created. - */ -#ifndef DEFAULT_UDP_RECVMBOX_SIZE -#define DEFAULT_UDP_RECVMBOX_SIZE 0 -#endif - -/** - * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a - * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed - * to sys_mbox_new() when the recvmbox is created. - */ -#ifndef DEFAULT_TCP_RECVMBOX_SIZE -#define DEFAULT_TCP_RECVMBOX_SIZE 0 -#endif - -/** - * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. - * The queue size value itself is platform-dependent, but is passed to - * sys_mbox_new() when the acceptmbox is created. - */ -#ifndef DEFAULT_ACCEPTMBOX_SIZE -#define DEFAULT_ACCEPTMBOX_SIZE 0 -#endif - -/* - ---------------------------------------------- - ---------- Sequential layer options ---------- - ---------------------------------------------- -*/ -/** - * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) - * Don't use it if you're not an active lwIP project member - */ -#ifndef LWIP_TCPIP_CORE_LOCKING -#define LWIP_TCPIP_CORE_LOCKING 0 -#endif - -/** - * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!) - * Don't use it if you're not an active lwIP project member - */ -#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT -#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 -#endif - -/** - * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) - */ -#ifndef LWIP_NETCONN -#define LWIP_NETCONN 0 -#endif - -/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create - * timers running in tcpip_thread from another thread. - */ -#ifndef LWIP_TCPIP_TIMEOUT -#define LWIP_TCPIP_TIMEOUT 1 -#endif - -/* - ------------------------------------ - ---------- Socket options ---------- - ------------------------------------ -*/ -/** - * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) - */ -#ifndef LWIP_SOCKET -#define LWIP_SOCKET 0 -#endif - -/** - * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names. - * (only used if you use sockets.c) - */ -#ifndef LWIP_COMPAT_SOCKETS -#define LWIP_COMPAT_SOCKETS 1 -#endif - -/** - * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. - * Disable this option if you use a POSIX operating system that uses the same - * names (read, write & close). (only used if you use sockets.c) - */ -#ifndef LWIP_POSIX_SOCKETS_IO_NAMES -#define LWIP_POSIX_SOCKETS_IO_NAMES 1 -#endif - -/** - * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT - * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set - * in seconds. (does not require sockets.c, and will affect tcp.c) - */ -#ifndef LWIP_TCP_KEEPALIVE -#define LWIP_TCP_KEEPALIVE 0 -#endif - -/** - * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing. - */ -#ifndef LWIP_SO_RCVTIMEO -#define LWIP_SO_RCVTIMEO 0 -#endif - -/** - * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. - */ -#ifndef LWIP_SO_RCVBUF -#define LWIP_SO_RCVBUF 0 -#endif - -/** - * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. - */ -#ifndef RECV_BUFSIZE_DEFAULT -#define RECV_BUFSIZE_DEFAULT INT_MAX -#endif - -/** - * SO_REUSE==1: Enable SO_REUSEADDR option. - */ -#ifndef SO_REUSE -#define SO_REUSE 0 -#endif - -/** - * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets - * to all local matches if SO_REUSEADDR is turned on. - * WARNING: Adds a memcpy for every packet if passing to more than one pcb! - */ -#ifndef SO_REUSE_RXTOALL -#define SO_REUSE_RXTOALL 0 -#endif - -/* - ---------------------------------------- - ---------- Statistics options ---------- - ---------------------------------------- -*/ -/** - * LWIP_STATS==1: Enable statistics collection in lwip_stats. - */ -#ifndef LWIP_STATS -#define LWIP_STATS 1 -#endif - -#if LWIP_STATS - -/** - * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. - */ -#ifndef LWIP_STATS_DISPLAY -#define LWIP_STATS_DISPLAY 0 -#endif - -/** - * LINK_STATS==1: Enable link stats. - */ -#ifndef LINK_STATS -#define LINK_STATS 1 -#endif - -/** - * ETHARP_STATS==1: Enable etharp stats. - */ -#ifndef ETHARP_STATS -#define ETHARP_STATS (LWIP_ARP) -#endif - -/** - * IP_STATS==1: Enable IP stats. - */ -#ifndef IP_STATS -#define IP_STATS 1 -#endif - -/** - * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is - * on if using either frag or reass. - */ -#ifndef IPFRAG_STATS -#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) -#endif - -/** - * ICMP_STATS==1: Enable ICMP stats. - */ -#ifndef ICMP_STATS -#define ICMP_STATS 1 -#endif - -/** - * IGMP_STATS==1: Enable IGMP stats. - */ -#ifndef IGMP_STATS -#define IGMP_STATS (LWIP_IGMP) -#endif - -/** - * UDP_STATS==1: Enable UDP stats. Default is on if - * UDP enabled, otherwise off. - */ -#ifndef UDP_STATS -#define UDP_STATS (LWIP_UDP) -#endif - -/** - * TCP_STATS==1: Enable TCP stats. Default is on if TCP - * enabled, otherwise off. - */ -#ifndef TCP_STATS -#define TCP_STATS (LWIP_TCP) -#endif - -/** - * MEM_STATS==1: Enable mem.c stats. - */ -#ifndef MEM_STATS -#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) -#endif - -/** - * MEMP_STATS==1: Enable memp.c pool stats. - */ -#ifndef MEMP_STATS -#define MEMP_STATS (MEMP_MEM_MALLOC == 0) -#endif - -/** - * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). - */ -#ifndef SYS_STATS -#define SYS_STATS (NO_SYS == 0) -#endif - -#else - -#define LINK_STATS 0 -#define IP_STATS 0 -#define IPFRAG_STATS 0 -#define ICMP_STATS 0 -#define IGMP_STATS 0 -#define UDP_STATS 0 -#define TCP_STATS 0 -#define MEM_STATS 0 -#define MEMP_STATS 0 -#define SYS_STATS 0 -#define LWIP_STATS_DISPLAY 0 - -#endif /* LWIP_STATS */ - -/* - --------------------------------- - ---------- PPP options ---------- - --------------------------------- -*/ -/** - * PPP_SUPPORT==1: Enable PPP. - */ -#ifndef PPP_SUPPORT -#define PPP_SUPPORT 0 -#endif - -/** - * PPPOE_SUPPORT==1: Enable PPP Over Ethernet - */ -#ifndef PPPOE_SUPPORT -#define PPPOE_SUPPORT 0 -#endif - -/** - * PPPOS_SUPPORT==1: Enable PPP Over Serial - */ -#ifndef PPPOS_SUPPORT -#define PPPOS_SUPPORT PPP_SUPPORT -#endif - -#if PPP_SUPPORT - -/** - * NUM_PPP: Max PPP sessions. - */ -#ifndef NUM_PPP -#define NUM_PPP 1 -#endif - -/** - * PAP_SUPPORT==1: Support PAP. - */ -#ifndef PAP_SUPPORT -#define PAP_SUPPORT 0 -#endif - -/** - * CHAP_SUPPORT==1: Support CHAP. - */ -#ifndef CHAP_SUPPORT -#define CHAP_SUPPORT 0 -#endif - -/** - * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET! - */ -#ifndef MSCHAP_SUPPORT -#define MSCHAP_SUPPORT 0 -#endif - -/** - * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! - */ -#ifndef CBCP_SUPPORT -#define CBCP_SUPPORT 0 -#endif - -/** - * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET! - */ -#ifndef CCP_SUPPORT -#define CCP_SUPPORT 0 -#endif - -/** - * VJ_SUPPORT==1: Support VJ header compression. - */ -#ifndef VJ_SUPPORT -#define VJ_SUPPORT 0 -#endif - -/** - * MD5_SUPPORT==1: Support MD5 (see also CHAP). - */ -#ifndef MD5_SUPPORT -#define MD5_SUPPORT 0 -#endif - -/* - * Timeouts - */ -#ifndef FSM_DEFTIMEOUT -#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */ -#endif - -#ifndef FSM_DEFMAXTERMREQS -#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ -#endif - -#ifndef FSM_DEFMAXCONFREQS -#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ -#endif - -#ifndef FSM_DEFMAXNAKLOOPS -#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ -#endif - -#ifndef UPAP_DEFTIMEOUT -#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ -#endif - -#ifndef UPAP_DEFREQTIME -#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ -#endif - -#ifndef CHAP_DEFTIMEOUT -#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */ -#endif - -#ifndef CHAP_DEFTRANSMITS -#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ -#endif - -/* Interval in seconds between keepalive echo requests, 0 to disable. */ -#ifndef LCP_ECHOINTERVAL -#define LCP_ECHOINTERVAL 0 -#endif - -/* Number of unanswered echo requests before failure. */ -#ifndef LCP_MAXECHOFAILS -#define LCP_MAXECHOFAILS 3 -#endif - -/* Max Xmit idle time (in jiffies) before resend flag char. */ -#ifndef PPP_MAXIDLEFLAG -#define PPP_MAXIDLEFLAG 100 -#endif - -/* - * Packet sizes - * - * Note - lcp shouldn't be allowed to negotiate stuff outside these - * limits. See lcp.h in the pppd directory. - * (XXX - these constants should simply be shared by lcp.c instead - * of living in lcp.h) - */ -#define PPP_MTU 1500 /* Default MTU (size of Info field) */ -#ifndef PPP_MAXMTU -/* #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) */ -#define PPP_MAXMTU 1500 /* Largest MTU we allow */ -#endif -#define PPP_MINMTU 64 -#define PPP_MRU 1500 /* default MRU = max length of info field */ -#define PPP_MAXMRU 1500 /* Largest MRU we allow */ -#ifndef PPP_DEFMRU -#define PPP_DEFMRU 296 /* Try for this */ -#endif -#define PPP_MINMRU 128 /* No MRUs below this */ - -#ifndef MAXNAMELEN -#define MAXNAMELEN 256 /* max length of hostname or name for auth */ -#endif -#ifndef MAXSECRETLEN -#define MAXSECRETLEN 256 /* max length of password or secret */ -#endif - -#endif /* PPP_SUPPORT */ - -/* - -------------------------------------- - ---------- Checksum options ---------- - -------------------------------------- -*/ -/** - * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. - */ -#ifndef CHECKSUM_GEN_IP -#define CHECKSUM_GEN_IP 1 -#endif - -/** - * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. - */ -#ifndef CHECKSUM_GEN_UDP -#define CHECKSUM_GEN_UDP 1 -#endif - -/** - * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. - */ -#ifndef CHECKSUM_GEN_TCP -#define CHECKSUM_GEN_TCP 1 -#endif - -/** - * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. - */ -#ifndef CHECKSUM_CHECK_IP -#define CHECKSUM_CHECK_IP 1 -#endif - -/** - * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. - */ -#ifndef CHECKSUM_CHECK_UDP -#define CHECKSUM_CHECK_UDP 1 -#endif - -/** - * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. - */ -#ifndef CHECKSUM_CHECK_TCP -#define CHECKSUM_CHECK_TCP 1 -#endif - -/** - * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from - * application buffers to pbufs. - */ -#ifndef LWIP_CHECKSUM_ON_COPY -#define LWIP_CHECKSUM_ON_COPY 0 -#endif - -/* - --------------------------------------- - ---------- Debugging options ---------- - --------------------------------------- -*/ -/** - * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is - * compared against this value. If it is smaller, then debugging - * messages are written. - */ -#ifndef LWIP_DBG_MIN_LEVEL -#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL -#endif - -/** - * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable - * debug messages of certain types. - */ -#ifndef LWIP_DBG_TYPES_ON -#define LWIP_DBG_TYPES_ON LWIP_DBG_ON -#endif - -/** - * ETHARP_DEBUG: Enable debugging in etharp.c. - */ -#ifndef ETHARP_DEBUG -#define ETHARP_DEBUG LWIP_DBG_OFF -#endif - -/** - * NETIF_DEBUG: Enable debugging in netif.c. - */ -#ifndef NETIF_DEBUG -#define NETIF_DEBUG LWIP_DBG_OFF -#endif - -/** - * PBUF_DEBUG: Enable debugging in pbuf.c. - */ -#ifndef PBUF_DEBUG -#define PBUF_DEBUG LWIP_DBG_OFF -#endif - -/** - * API_LIB_DEBUG: Enable debugging in api_lib.c. - */ -#ifndef API_LIB_DEBUG -#define API_LIB_DEBUG LWIP_DBG_OFF -#endif - -/** - * API_MSG_DEBUG: Enable debugging in api_msg.c. - */ -#ifndef API_MSG_DEBUG -#define API_MSG_DEBUG LWIP_DBG_OFF -#endif - -/** - * SOCKETS_DEBUG: Enable debugging in sockets.c. - */ -#ifndef SOCKETS_DEBUG -#define SOCKETS_DEBUG LWIP_DBG_OFF -#endif - -/** - * ICMP_DEBUG: Enable debugging in icmp.c. - */ -#ifndef ICMP_DEBUG -#define ICMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * IGMP_DEBUG: Enable debugging in igmp.c. - */ -#ifndef IGMP_DEBUG -#define IGMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * INET_DEBUG: Enable debugging in inet.c. - */ -#ifndef INET_DEBUG -#define INET_DEBUG LWIP_DBG_OFF -#endif - -/** - * IP_DEBUG: Enable debugging for IP. - */ -#ifndef IP_DEBUG -#define IP_DEBUG LWIP_DBG_OFF -#endif - -/** - * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. - */ -#ifndef IP_REASS_DEBUG -#define IP_REASS_DEBUG LWIP_DBG_OFF -#endif - -/** - * RAW_DEBUG: Enable debugging in raw.c. - */ -#ifndef RAW_DEBUG -#define RAW_DEBUG LWIP_DBG_OFF -#endif - -/** - * MEM_DEBUG: Enable debugging in mem.c. - */ -#ifndef MEM_DEBUG -#define MEM_DEBUG LWIP_DBG_OFF -#endif - -/** - * MEMP_DEBUG: Enable debugging in memp.c. - */ -#ifndef MEMP_DEBUG -#define MEMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * SYS_DEBUG: Enable debugging in sys.c. - */ -#ifndef SYS_DEBUG -#define SYS_DEBUG LWIP_DBG_OFF -#endif - -/** - * TIMERS_DEBUG: Enable debugging in timers.c. - */ -#ifndef TIMERS_DEBUG -#define TIMERS_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_DEBUG: Enable debugging for TCP. - */ -#ifndef TCP_DEBUG -#define TCP_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. - */ -#ifndef TCP_INPUT_DEBUG -#define TCP_INPUT_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. - */ -#ifndef TCP_FR_DEBUG -#define TCP_FR_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit - * timeout. - */ -#ifndef TCP_RTO_DEBUG -#define TCP_RTO_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. - */ -#ifndef TCP_CWND_DEBUG -#define TCP_CWND_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. - */ -#ifndef TCP_WND_DEBUG -#define TCP_WND_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. - */ -#ifndef TCP_OUTPUT_DEBUG -#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. - */ -#ifndef TCP_RST_DEBUG -#define TCP_RST_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. - */ -#ifndef TCP_QLEN_DEBUG -#define TCP_QLEN_DEBUG LWIP_DBG_OFF -#endif - -/** - * UDP_DEBUG: Enable debugging in UDP. - */ -#ifndef UDP_DEBUG -#define UDP_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCPIP_DEBUG: Enable debugging in tcpip.c. - */ -#ifndef TCPIP_DEBUG -#define TCPIP_DEBUG LWIP_DBG_OFF -#endif - -/** - * PPP_DEBUG: Enable debugging for PPP. - */ -#ifndef PPP_DEBUG -#define PPP_DEBUG LWIP_DBG_OFF -#endif - -/** - * SLIP_DEBUG: Enable debugging in slipif.c. - */ -#ifndef SLIP_DEBUG -#define SLIP_DEBUG LWIP_DBG_OFF -#endif - -/** - * DHCP_DEBUG: Enable debugging in dhcp.c. - */ -#ifndef DHCP_DEBUG -#define DHCP_DEBUG LWIP_DBG_OFF -#endif - -/** - * AUTOIP_DEBUG: Enable debugging in autoip.c. - */ -#ifndef AUTOIP_DEBUG -#define AUTOIP_DEBUG LWIP_DBG_OFF -#endif - -/** - * SNMP_MSG_DEBUG: Enable debugging for SNMP messages. - */ -#ifndef SNMP_MSG_DEBUG -#define SNMP_MSG_DEBUG LWIP_DBG_OFF -#endif - -/** - * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. - */ -#ifndef SNMP_MIB_DEBUG -#define SNMP_MIB_DEBUG LWIP_DBG_OFF -#endif - -/** - * DNS_DEBUG: Enable debugging for DNS. - */ -#ifndef DNS_DEBUG -#define DNS_DEBUG LWIP_DBG_OFF -#endif - -#endif /* __LWIP_OPT_H__ */ diff --git a/tools/sdk/lwip/include/lwip/pbuf.h b/tools/sdk/lwip/include/lwip/pbuf.h deleted file mode 100644 index 3d24db4d4..000000000 --- a/tools/sdk/lwip/include/lwip/pbuf.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#ifndef __LWIP_PBUF_H__ -#define __LWIP_PBUF_H__ - -#include "lwip/opt.h" -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Currently, the pbuf_custom code is only needed for one specific configuration - * of IP_FRAG */ -#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) - -#define PBUF_TRANSPORT_HLEN 20 -#define PBUF_IP_HLEN 20 - -typedef enum { - PBUF_TRANSPORT, - PBUF_IP, - PBUF_LINK, - PBUF_RAW -} pbuf_layer; - -typedef enum { - PBUF_RAM, /* pbuf data is stored in RAM */ - PBUF_ROM, /* pbuf data is stored in ROM */ - PBUF_REF, /* pbuf comes from the pbuf pool */ - PBUF_POOL, /* pbuf payload refers to RAM */ -#ifdef EBUF_LWIP - PBUF_ESF_RX /* pbuf payload is from WLAN */ -#endif /* ESF_LWIP */ -} pbuf_type; - - -/** indicates this packet's data should be immediately passed to the application */ -#define PBUF_FLAG_PUSH 0x01U -/** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a - a pbuf differently */ -#define PBUF_FLAG_IS_CUSTOM 0x02U -/** indicates this pbuf is UDP multicast to be looped back */ -#define PBUF_FLAG_MCASTLOOP 0x04U - -struct pbuf { - /** next pbuf in singly linked pbuf chain */ - struct pbuf *next; - - /** pointer to the actual data in the buffer */ - void *payload; - - /** - * total length of this buffer and all next buffers in chain - * belonging to the same packet. - * - * For non-queue packet chains this is the invariant: - * p->tot_len == p->len + (p->next? p->next->tot_len: 0) - */ - u16_t tot_len; - - /** length of this buffer */ - u16_t len; - - /** pbuf_type as u8_t instead of enum to save space */ - u8_t /*pbuf_type*/ type; - - /** misc flags */ - u8_t flags; - - /** - * the reference count always equals the number of pointers - * that refer to this pbuf. This can be pointers from an application, - * the stack itself, or pbuf->next pointers from a chain. - */ - u16_t ref; - - /* add a pointer for esf_buf */ - void * eb; -}; - -#if LWIP_SUPPORT_CUSTOM_PBUF -/** Prototype for a function to free a custom pbuf */ -typedef void (*pbuf_free_custom_fn)(struct pbuf *p); - -/** A custom pbuf: like a pbuf, but following a function pointer to free it. */ -struct pbuf_custom { - /** The actual pbuf */ - struct pbuf pbuf; - /** This function is called when pbuf_free deallocates this pbuf(_custom) */ - pbuf_free_custom_fn custom_free_function; -}; -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ - -/* Initializes the pbuf module. This call is empty for now, but may not be in future. */ -#define pbuf_init() - -struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type)ICACHE_FLASH_ATTR; -#if LWIP_SUPPORT_CUSTOM_PBUF -struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, - struct pbuf_custom *p, void *payload_mem, - u16_t payload_mem_len)ICACHE_FLASH_ATTR; -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ -void pbuf_realloc(struct pbuf *p, u16_t size)ICACHE_FLASH_ATTR; -u8_t pbuf_header(struct pbuf *p, s16_t header_size)ICACHE_FLASH_ATTR; -void pbuf_ref(struct pbuf *p)ICACHE_FLASH_ATTR; -u8_t pbuf_free(struct pbuf *p)ICACHE_FLASH_ATTR; -u8_t pbuf_clen(struct pbuf *p)ICACHE_FLASH_ATTR; -void pbuf_cat(struct pbuf *head, struct pbuf *tail)ICACHE_FLASH_ATTR; -void pbuf_chain(struct pbuf *head, struct pbuf *tail)ICACHE_FLASH_ATTR; -struct pbuf *pbuf_dechain(struct pbuf *p)ICACHE_FLASH_ATTR; -err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)ICACHE_FLASH_ATTR; -u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset)ICACHE_FLASH_ATTR; -err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)ICACHE_FLASH_ATTR; -struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer)ICACHE_FLASH_ATTR; -#if LWIP_CHECKSUM_ON_COPY -err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, - u16_t len, u16_t *chksum)ICACHE_FLASH_ATTR; -#endif /* LWIP_CHECKSUM_ON_COPY */ - -u8_t pbuf_get_at(struct pbuf* p, u16_t offset)ICACHE_FLASH_ATTR; -u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)ICACHE_FLASH_ATTR; -u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)ICACHE_FLASH_ATTR; -u16_t pbuf_strstr(struct pbuf* p, const char* substr)ICACHE_FLASH_ATTR; - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_PBUF_H__ */ diff --git a/tools/sdk/lwip/include/lwip/puck_def.h b/tools/sdk/lwip/include/lwip/puck_def.h deleted file mode 100644 index c20027a15..000000000 --- a/tools/sdk/lwip/include/lwip/puck_def.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * puck_def.h - * - * Created on: Jul 22, 2010 - * Author: dtoma - */ - -#ifndef PUCK_DEF_H_ -#define PUCK_DEF_H_ - - - -#define INSTRUMENT_PORT 8760 - -#define INSTRUMENT_LENGTH 80 - -#define MDNS_NAME_LENGTH 68 //68 - -char* PUCK_SERVICE = NULL; -//#define PUCK_SERVICE "_Escpressif._tcp.local" -#define DNS_SD_SERVICE "_services._dns-sd._udp.local" -#define SERVICE_DESCRIPTION "PUCK PROTOCOL" -#define PUCK_SERVICE_LENGTH 30 - -#define UUID_LEN 16 -#define DS_VERS_LEN 2 -#define DS_SIZE_LEN 2 -#define MAN_ID_LEN 4 -#define MAN_MODEL_LEN 2 -#define MAN_VERS_LEN 2 -#define SER_NUM_LEN 4 -#define NAME_LEN 64 -#define PUCK_DATASHEET_SIZE 96 - -#define UUID_OFFSET 0 -#define DS_VERS_OFFSET UUID_LEN + UUID_OFFSET -#define DS_SIZE_OFFSET DS_VERS_LEN + DS_VERS_OFFSET -#define MAN_ID_OFFSET DS_SIZE_LEN + DS_SIZE_OFFSET -#define MAN_MODEL_OFFSET MAN_ID_LEN + MAN_ID_OFFSET -#define MAN_VERS_OFFSET MAN_MODEL_LEN + MAN_MODEL_OFFSET -#define SER_NUM_OFFSET MAN_VERS_LEN + MAN_VERS_OFFSET -#define NAME_OFFSET SER_NUM_LEN + SER_NUM_OFFSET - -#endif /* __PUCK_DEF_H__ */ diff --git a/tools/sdk/lwip/include/lwip/raw.h b/tools/sdk/lwip/include/lwip/raw.h deleted file mode 100644 index c9c40871b..000000000 --- a/tools/sdk/lwip/include/lwip/raw.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_RAW_H__ -#define __LWIP_RAW_H__ - -#include "lwip/opt.h" - -#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/pbuf.h" -#include "lwip/def.h" -#include "lwip/ip.h" -#include "lwip/ip_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct raw_pcb; - -/** Function prototype for raw pcb receive callback functions. - * @param arg user supplied argument (raw_pcb.recv_arg) - * @param pcb the raw_pcb which received data - * @param p the packet buffer that was received - * @param addr the remote IP address from which the packet was received - * @return 1 if the packet was 'eaten' (aka. deleted), - * 0 if the packet lives on - * If returning 1, the callback is responsible for freeing the pbuf - * if it's not used any more. - */ -typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, - ip_addr_t *addr); - -struct raw_pcb { - /* Common members of all PCB types */ - IP_PCB; - - struct raw_pcb *next; - - u8_t protocol; - - /** receive callback function */ - raw_recv_fn recv; - /* user-supplied argument for the recv callback */ - void *recv_arg; -}; - -/* The following functions is the application layer interface to the - RAW code. */ -struct raw_pcb * raw_new (u8_t proto)ICACHE_FLASH_ATTR; -void raw_remove (struct raw_pcb *pcb)ICACHE_FLASH_ATTR; -err_t raw_bind (struct raw_pcb *pcb, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; -err_t raw_connect (struct raw_pcb *pcb, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; - -void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)ICACHE_FLASH_ATTR; -err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; -err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); - -/* The following functions are the lower layer interface to RAW. */ -u8_t raw_input (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; -#define raw_init() /* Compatibility define, not init needed. */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_RAW */ - -#endif /* __LWIP_RAW_H__ */ diff --git a/tools/sdk/lwip/include/lwip/sio.h b/tools/sdk/lwip/include/lwip/sio.h deleted file mode 100644 index 228c85777..000000000 --- a/tools/sdk/lwip/include/lwip/sio.h +++ /dev/null @@ -1,141 +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. - */ - -/* - * This is the interface to the platform specific serial IO module - * It needs to be implemented by those platforms which need SLIP or PPP - */ - -#ifndef __SIO_H__ -#define __SIO_H__ - -#include "lwip/arch.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* If you want to define sio_fd_t elsewhere or differently, - define this in your cc.h file. */ -#ifndef __sio_fd_t_defined -typedef void * sio_fd_t; -#endif - -/* The following functions can be defined to something else in your cc.h file - or be implemented in your custom sio.c file. */ - -#ifndef sio_open -/** - * Opens a serial device for communication. - * - * @param devnum device number - * @return handle to serial device if successful, NULL otherwise - */ -sio_fd_t sio_open(u8_t devnum)ICACHE_FLASH_ATTR; -#endif - -#ifndef sio_send -/** - * Sends a single character to the serial device. - * - * @param c character to send - * @param fd serial device handle - * - * @note This function will block until the character can be sent. - */ -void sio_send(u8_t c, sio_fd_t fd)ICACHE_FLASH_ATTR; -#endif - -#ifndef sio_recv -/** - * Receives a single character from the serial device. - * - * @param fd serial device handle - * - * @note This function will block until a character is received. - */ -u8_t sio_recv(sio_fd_t fd)ICACHE_FLASH_ATTR; -#endif - -#ifndef sio_read -/** - * Reads from the serial device. - * - * @param fd serial device handle - * @param data pointer to data buffer for receiving - * @param len maximum length (in bytes) of data to receive - * @return number of bytes actually received - may be 0 if aborted by sio_read_abort - * - * @note This function will block until data can be received. The blocking - * can be cancelled by calling sio_read_abort(). - */ -u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR; -#endif - -#ifndef sio_tryread -/** - * Tries to read from the serial device. Same as sio_read but returns - * immediately if no data is available and never blocks. - * - * @param fd serial device handle - * @param data pointer to data buffer for receiving - * @param len maximum length (in bytes) of data to receive - * @return number of bytes actually received - */ -u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR; -#endif - -#ifndef sio_write -/** - * Writes to the serial device. - * - * @param fd serial device handle - * @param data pointer to data to send - * @param len length (in bytes) of data to send - * @return number of bytes actually sent - * - * @note This function will block until all data can be sent. - */ -u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR; -#endif - -#ifndef sio_read_abort -/** - * Aborts a blocking sio_read() call. - * - * @param fd serial device handle - */ -void sio_read_abort(sio_fd_t fd)ICACHE_FLASH_ATTR; -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __SIO_H__ */ diff --git a/tools/sdk/lwip/include/lwip/snmp.h b/tools/sdk/lwip/include/lwip/snmp.h deleted file mode 100644 index 2ed043dd5..000000000 --- a/tools/sdk/lwip/include/lwip/snmp.h +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (c) 2001, 2002 Leon Woestenberg - * Copyright (c) 2001, 2002 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. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Leon Woestenberg - * - */ -#ifndef __LWIP_SNMP_H__ -#define __LWIP_SNMP_H__ - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#include "lwip/ip_addr.h" - -struct udp_pcb; -struct netif; - -/** - * @see RFC1213, "MIB-II, 6. Definitions" - */ -enum snmp_ifType { - snmp_ifType_other=1, /* none of the following */ - snmp_ifType_regular1822, - snmp_ifType_hdh1822, - snmp_ifType_ddn_x25, - snmp_ifType_rfc877_x25, - snmp_ifType_ethernet_csmacd, - snmp_ifType_iso88023_csmacd, - snmp_ifType_iso88024_tokenBus, - snmp_ifType_iso88025_tokenRing, - snmp_ifType_iso88026_man, - snmp_ifType_starLan, - snmp_ifType_proteon_10Mbit, - snmp_ifType_proteon_80Mbit, - snmp_ifType_hyperchannel, - snmp_ifType_fddi, - snmp_ifType_lapb, - snmp_ifType_sdlc, - snmp_ifType_ds1, /* T-1 */ - snmp_ifType_e1, /* european equiv. of T-1 */ - snmp_ifType_basicISDN, - snmp_ifType_primaryISDN, /* proprietary serial */ - snmp_ifType_propPointToPointSerial, - snmp_ifType_ppp, - snmp_ifType_softwareLoopback, - snmp_ifType_eon, /* CLNP over IP [11] */ - snmp_ifType_ethernet_3Mbit, - snmp_ifType_nsip, /* XNS over IP */ - snmp_ifType_slip, /* generic SLIP */ - snmp_ifType_ultra, /* ULTRA technologies */ - snmp_ifType_ds3, /* T-3 */ - snmp_ifType_sip, /* SMDS */ - snmp_ifType_frame_relay -}; - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -/** SNMP "sysuptime" Interval */ -#define SNMP_SYSUPTIME_INTERVAL 10 - -/** fixed maximum length for object identifier type */ -#define LWIP_SNMP_OBJ_ID_LEN 32 - -/** internal object identifier representation */ -struct snmp_obj_id -{ - u8_t len; - s32_t id[LWIP_SNMP_OBJ_ID_LEN]; -}; - -/* system */ -void snmp_set_sysdesr(u8_t* str, u8_t* len); -void snmp_set_sysobjid(struct snmp_obj_id *oid); -void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid); -void snmp_inc_sysuptime(void); -void snmp_add_sysuptime(u32_t value); -void snmp_get_sysuptime(u32_t *value); -void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen); -void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen); -void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen); - -/* network interface */ -void snmp_add_ifinoctets(struct netif *ni, u32_t value); -void snmp_inc_ifinucastpkts(struct netif *ni); -void snmp_inc_ifinnucastpkts(struct netif *ni); -void snmp_inc_ifindiscards(struct netif *ni); -void snmp_add_ifoutoctets(struct netif *ni, u32_t value); -void snmp_inc_ifoutucastpkts(struct netif *ni); -void snmp_inc_ifoutnucastpkts(struct netif *ni); -void snmp_inc_ifoutdiscards(struct netif *ni); -void snmp_inc_iflist(void); -void snmp_dec_iflist(void); - -/* ARP (for atTable and ipNetToMediaTable) */ -void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip); -void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip); - -/* IP */ -void snmp_inc_ipinreceives(void); -void snmp_inc_ipinhdrerrors(void); -void snmp_inc_ipinaddrerrors(void); -void snmp_inc_ipforwdatagrams(void); -void snmp_inc_ipinunknownprotos(void); -void snmp_inc_ipindiscards(void); -void snmp_inc_ipindelivers(void); -void snmp_inc_ipoutrequests(void); -void snmp_inc_ipoutdiscards(void); -void snmp_inc_ipoutnoroutes(void); -void snmp_inc_ipreasmreqds(void); -void snmp_inc_ipreasmoks(void); -void snmp_inc_ipreasmfails(void); -void snmp_inc_ipfragoks(void); -void snmp_inc_ipfragfails(void); -void snmp_inc_ipfragcreates(void); -void snmp_inc_iproutingdiscards(void); -void snmp_insert_ipaddridx_tree(struct netif *ni); -void snmp_delete_ipaddridx_tree(struct netif *ni); -void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni); -void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni); - -/* ICMP */ -void snmp_inc_icmpinmsgs(void); -void snmp_inc_icmpinerrors(void); -void snmp_inc_icmpindestunreachs(void); -void snmp_inc_icmpintimeexcds(void); -void snmp_inc_icmpinparmprobs(void); -void snmp_inc_icmpinsrcquenchs(void); -void snmp_inc_icmpinredirects(void); -void snmp_inc_icmpinechos(void); -void snmp_inc_icmpinechoreps(void); -void snmp_inc_icmpintimestamps(void); -void snmp_inc_icmpintimestampreps(void); -void snmp_inc_icmpinaddrmasks(void); -void snmp_inc_icmpinaddrmaskreps(void); -void snmp_inc_icmpoutmsgs(void); -void snmp_inc_icmpouterrors(void); -void snmp_inc_icmpoutdestunreachs(void); -void snmp_inc_icmpouttimeexcds(void); -void snmp_inc_icmpoutparmprobs(void); -void snmp_inc_icmpoutsrcquenchs(void); -void snmp_inc_icmpoutredirects(void); -void snmp_inc_icmpoutechos(void); -void snmp_inc_icmpoutechoreps(void); -void snmp_inc_icmpouttimestamps(void); -void snmp_inc_icmpouttimestampreps(void); -void snmp_inc_icmpoutaddrmasks(void); -void snmp_inc_icmpoutaddrmaskreps(void); - -/* TCP */ -void snmp_inc_tcpactiveopens(void); -void snmp_inc_tcppassiveopens(void); -void snmp_inc_tcpattemptfails(void); -void snmp_inc_tcpestabresets(void); -void snmp_inc_tcpinsegs(void); -void snmp_inc_tcpoutsegs(void); -void snmp_inc_tcpretranssegs(void); -void snmp_inc_tcpinerrs(void); -void snmp_inc_tcpoutrsts(void); - -/* UDP */ -void snmp_inc_udpindatagrams(void); -void snmp_inc_udpnoports(void); -void snmp_inc_udpinerrors(void); -void snmp_inc_udpoutdatagrams(void); -void snmp_insert_udpidx_tree(struct udp_pcb *pcb); -void snmp_delete_udpidx_tree(struct udp_pcb *pcb); - -/* SNMP */ -void snmp_inc_snmpinpkts(void); -void snmp_inc_snmpoutpkts(void); -void snmp_inc_snmpinbadversions(void); -void snmp_inc_snmpinbadcommunitynames(void); -void snmp_inc_snmpinbadcommunityuses(void); -void snmp_inc_snmpinasnparseerrs(void); -void snmp_inc_snmpintoobigs(void); -void snmp_inc_snmpinnosuchnames(void); -void snmp_inc_snmpinbadvalues(void); -void snmp_inc_snmpinreadonlys(void); -void snmp_inc_snmpingenerrs(void); -void snmp_add_snmpintotalreqvars(u8_t value); -void snmp_add_snmpintotalsetvars(u8_t value); -void snmp_inc_snmpingetrequests(void); -void snmp_inc_snmpingetnexts(void); -void snmp_inc_snmpinsetrequests(void); -void snmp_inc_snmpingetresponses(void); -void snmp_inc_snmpintraps(void); -void snmp_inc_snmpouttoobigs(void); -void snmp_inc_snmpoutnosuchnames(void); -void snmp_inc_snmpoutbadvalues(void); -void snmp_inc_snmpoutgenerrs(void); -void snmp_inc_snmpoutgetrequests(void); -void snmp_inc_snmpoutgetnexts(void); -void snmp_inc_snmpoutsetrequests(void); -void snmp_inc_snmpoutgetresponses(void); -void snmp_inc_snmpouttraps(void); -void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid); -void snmp_set_snmpenableauthentraps(u8_t *value); -void snmp_get_snmpenableauthentraps(u8_t *value); - -/* LWIP_SNMP support not available */ -/* define everything to be empty */ -#else - -/* system */ -#define snmp_set_sysdesr(str, len) -#define snmp_set_sysobjid(oid); -#define snmp_get_sysobjid_ptr(oid) -#define snmp_inc_sysuptime() -#define snmp_add_sysuptime(value) -#define snmp_get_sysuptime(value) -#define snmp_set_syscontact(ocstr, ocstrlen); -#define snmp_set_sysname(ocstr, ocstrlen); -#define snmp_set_syslocation(ocstr, ocstrlen); - -/* network interface */ -#define snmp_add_ifinoctets(ni,value) -#define snmp_inc_ifinucastpkts(ni) -#define snmp_inc_ifinnucastpkts(ni) -#define snmp_inc_ifindiscards(ni) -#define snmp_add_ifoutoctets(ni,value) -#define snmp_inc_ifoutucastpkts(ni) -#define snmp_inc_ifoutnucastpkts(ni) -#define snmp_inc_ifoutdiscards(ni) -#define snmp_inc_iflist() -#define snmp_dec_iflist() - -/* ARP */ -#define snmp_insert_arpidx_tree(ni,ip) -#define snmp_delete_arpidx_tree(ni,ip) - -/* IP */ -#define snmp_inc_ipinreceives() -#define snmp_inc_ipinhdrerrors() -#define snmp_inc_ipinaddrerrors() -#define snmp_inc_ipforwdatagrams() -#define snmp_inc_ipinunknownprotos() -#define snmp_inc_ipindiscards() -#define snmp_inc_ipindelivers() -#define snmp_inc_ipoutrequests() -#define snmp_inc_ipoutdiscards() -#define snmp_inc_ipoutnoroutes() -#define snmp_inc_ipreasmreqds() -#define snmp_inc_ipreasmoks() -#define snmp_inc_ipreasmfails() -#define snmp_inc_ipfragoks() -#define snmp_inc_ipfragfails() -#define snmp_inc_ipfragcreates() -#define snmp_inc_iproutingdiscards() -#define snmp_insert_ipaddridx_tree(ni) -#define snmp_delete_ipaddridx_tree(ni) -#define snmp_insert_iprteidx_tree(dflt, ni) -#define snmp_delete_iprteidx_tree(dflt, ni) - -/* ICMP */ -#define snmp_inc_icmpinmsgs() -#define snmp_inc_icmpinerrors() -#define snmp_inc_icmpindestunreachs() -#define snmp_inc_icmpintimeexcds() -#define snmp_inc_icmpinparmprobs() -#define snmp_inc_icmpinsrcquenchs() -#define snmp_inc_icmpinredirects() -#define snmp_inc_icmpinechos() -#define snmp_inc_icmpinechoreps() -#define snmp_inc_icmpintimestamps() -#define snmp_inc_icmpintimestampreps() -#define snmp_inc_icmpinaddrmasks() -#define snmp_inc_icmpinaddrmaskreps() -#define snmp_inc_icmpoutmsgs() -#define snmp_inc_icmpouterrors() -#define snmp_inc_icmpoutdestunreachs() -#define snmp_inc_icmpouttimeexcds() -#define snmp_inc_icmpoutparmprobs() -#define snmp_inc_icmpoutsrcquenchs() -#define snmp_inc_icmpoutredirects() -#define snmp_inc_icmpoutechos() -#define snmp_inc_icmpoutechoreps() -#define snmp_inc_icmpouttimestamps() -#define snmp_inc_icmpouttimestampreps() -#define snmp_inc_icmpoutaddrmasks() -#define snmp_inc_icmpoutaddrmaskreps() -/* TCP */ -#define snmp_inc_tcpactiveopens() -#define snmp_inc_tcppassiveopens() -#define snmp_inc_tcpattemptfails() -#define snmp_inc_tcpestabresets() -#define snmp_inc_tcpinsegs() -#define snmp_inc_tcpoutsegs() -#define snmp_inc_tcpretranssegs() -#define snmp_inc_tcpinerrs() -#define snmp_inc_tcpoutrsts() - -/* UDP */ -#define snmp_inc_udpindatagrams() -#define snmp_inc_udpnoports() -#define snmp_inc_udpinerrors() -#define snmp_inc_udpoutdatagrams() -#define snmp_insert_udpidx_tree(pcb) -#define snmp_delete_udpidx_tree(pcb) - -/* SNMP */ -#define snmp_inc_snmpinpkts() -#define snmp_inc_snmpoutpkts() -#define snmp_inc_snmpinbadversions() -#define snmp_inc_snmpinbadcommunitynames() -#define snmp_inc_snmpinbadcommunityuses() -#define snmp_inc_snmpinasnparseerrs() -#define snmp_inc_snmpintoobigs() -#define snmp_inc_snmpinnosuchnames() -#define snmp_inc_snmpinbadvalues() -#define snmp_inc_snmpinreadonlys() -#define snmp_inc_snmpingenerrs() -#define snmp_add_snmpintotalreqvars(value) -#define snmp_add_snmpintotalsetvars(value) -#define snmp_inc_snmpingetrequests() -#define snmp_inc_snmpingetnexts() -#define snmp_inc_snmpinsetrequests() -#define snmp_inc_snmpingetresponses() -#define snmp_inc_snmpintraps() -#define snmp_inc_snmpouttoobigs() -#define snmp_inc_snmpoutnosuchnames() -#define snmp_inc_snmpoutbadvalues() -#define snmp_inc_snmpoutgenerrs() -#define snmp_inc_snmpoutgetrequests() -#define snmp_inc_snmpoutgetnexts() -#define snmp_inc_snmpoutsetrequests() -#define snmp_inc_snmpoutgetresponses() -#define snmp_inc_snmpouttraps() -#define snmp_get_snmpgrpid_ptr(oid) -#define snmp_set_snmpenableauthentraps(value) -#define snmp_get_snmpenableauthentraps(value) - -#endif /* LWIP_SNMP */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_SNMP_H__ */ diff --git a/tools/sdk/lwip/include/lwip/snmp_asn1.h b/tools/sdk/lwip/include/lwip/snmp_asn1.h deleted file mode 100644 index 605fa3f16..000000000 --- a/tools/sdk/lwip/include/lwip/snmp_asn1.h +++ /dev/null @@ -1,101 +0,0 @@ -/** - * @file - * Abstract Syntax Notation One (ISO 8824, 8825) codec. - */ - -/* - * 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 - */ - -#ifndef __LWIP_SNMP_ASN1_H__ -#define __LWIP_SNMP_ASN1_H__ - -#include "lwip/opt.h" -#include "lwip/err.h" -#include "lwip/pbuf.h" -#include "lwip/snmp.h" - -#if LWIP_SNMP - -#ifdef __cplusplus -extern "C" { -#endif - -#define SNMP_ASN1_UNIV (0) /* (!0x80 | !0x40) */ -#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 | 0x40) */ -#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */ - -#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */ -#define SNMP_ASN1_PRIMIT (0) /* (!0x20) */ - -/* universal tags */ -#define SNMP_ASN1_INTEG 2 -#define SNMP_ASN1_OC_STR 4 -#define SNMP_ASN1_NUL 5 -#define SNMP_ASN1_OBJ_ID 6 -#define SNMP_ASN1_SEQ 16 - -/* application specific (SNMP) tags */ -#define SNMP_ASN1_IPADDR 0 /* octet string size(4) */ -#define SNMP_ASN1_COUNTER 1 /* u32_t */ -#define SNMP_ASN1_GAUGE 2 /* u32_t */ -#define SNMP_ASN1_TIMETICKS 3 /* u32_t */ -#define SNMP_ASN1_OPAQUE 4 /* octet string */ - -/* context specific (SNMP) tags */ -#define SNMP_ASN1_PDU_GET_REQ 0 -#define SNMP_ASN1_PDU_GET_NEXT_REQ 1 -#define SNMP_ASN1_PDU_GET_RESP 2 -#define SNMP_ASN1_PDU_SET_REQ 3 -#define SNMP_ASN1_PDU_TRAP 4 - -err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type); -err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length); -err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value); -err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value); -err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid); -err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw); - -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_s32t_cnt(s32_t value, u16_t *octets_needed); -void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed); -err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type); -err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length); -err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value); -err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value); -err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident); -err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SNMP */ - -#endif /* __LWIP_SNMP_ASN1_H__ */ diff --git a/tools/sdk/lwip/include/lwip/snmp_msg.h b/tools/sdk/lwip/include/lwip/snmp_msg.h deleted file mode 100644 index 1183e3a95..000000000 --- a/tools/sdk/lwip/include/lwip/snmp_msg.h +++ /dev/null @@ -1,315 +0,0 @@ -/** - * @file - * SNMP Agent message handling structures. - */ - -/* - * 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 - */ - -#ifndef __LWIP_SNMP_MSG_H__ -#define __LWIP_SNMP_MSG_H__ - -#include "lwip/opt.h" -#include "lwip/snmp.h" -#include "lwip/snmp_structs.h" -#include "lwip/ip_addr.h" -#include "lwip/err.h" - -#if LWIP_SNMP - -#if SNMP_PRIVATE_MIB -/* When using a private MIB, you have to create a file 'private_mib.h' that contains - * a 'struct mib_array_node mib_private' which contains your MIB. */ -#include "private_mib.h" -#endif - -#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 - -#define SNMP_ES_NOERROR 0 -#define SNMP_ES_TOOBIG 1 -#define SNMP_ES_NOSUCHNAME 2 -#define SNMP_ES_BADVALUE 3 -#define SNMP_ES_READONLY 4 -#define SNMP_ES_GENERROR 5 - -#define SNMP_GENTRAP_COLDSTART 0 -#define SNMP_GENTRAP_WARMSTART 1 -#define SNMP_GENTRAP_AUTHFAIL 4 -#define SNMP_GENTRAP_ENTERPRISESPC 6 - -struct snmp_varbind -{ - /* next pointer, NULL for last in list */ - struct snmp_varbind *next; - /* previous pointer, NULL for first in list */ - struct snmp_varbind *prev; - - /* object identifier length (in s32_t) */ - u8_t ident_len; - /* object identifier array */ - s32_t *ident; - - /* object value ASN1 type */ - u8_t value_type; - /* object value length (in u8_t) */ - u8_t value_len; - /* object value */ - void *value; - - /* encoding varbind seq length length */ - u8_t seqlenlen; - /* encoding object identifier length length */ - u8_t olenlen; - /* encoding object value length length */ - u8_t vlenlen; - /* encoding varbind seq length */ - u16_t seqlen; - /* encoding object identifier length */ - u16_t olen; - /* encoding object value length */ - u16_t vlen; -}; - -struct snmp_varbind_root -{ - struct snmp_varbind *head; - struct snmp_varbind *tail; - /* number of variable bindings in list */ - u8_t count; - /* encoding varbind-list seq length length */ - u8_t seqlenlen; - /* encoding varbind-list seq length */ - u16_t seqlen; -}; - -/** output response message header length fields */ -struct snmp_resp_header_lengths -{ - /* encoding error-index length length */ - u8_t erridxlenlen; - /* encoding error-status length length */ - u8_t errstatlenlen; - /* encoding request id length length */ - u8_t ridlenlen; - /* encoding pdu length length */ - u8_t pdulenlen; - /* encoding community length length */ - u8_t comlenlen; - /* encoding version length length */ - u8_t verlenlen; - /* encoding sequence length length */ - u8_t seqlenlen; - - /* encoding error-index length */ - u16_t erridxlen; - /* encoding error-status length */ - u16_t errstatlen; - /* encoding request id length */ - u16_t ridlen; - /* encoding pdu length */ - u16_t pdulen; - /* encoding community length */ - u16_t comlen; - /* encoding version length */ - u16_t verlen; - /* encoding sequence length */ - u16_t seqlen; -}; - -/** output response message header length fields */ -struct snmp_trap_header_lengths -{ - /* encoding timestamp length length */ - u8_t tslenlen; - /* encoding specific-trap length length */ - u8_t strplenlen; - /* encoding generic-trap length length */ - u8_t gtrplenlen; - /* encoding agent-addr length length */ - u8_t aaddrlenlen; - /* encoding enterprise-id length length */ - u8_t eidlenlen; - /* encoding pdu length length */ - u8_t pdulenlen; - /* encoding community length length */ - u8_t comlenlen; - /* encoding version length length */ - u8_t verlenlen; - /* encoding sequence length length */ - u8_t seqlenlen; - - /* encoding timestamp length */ - u16_t tslen; - /* encoding specific-trap length */ - u16_t strplen; - /* encoding generic-trap length */ - u16_t gtrplen; - /* encoding agent-addr length */ - u16_t aaddrlen; - /* encoding enterprise-id length */ - u16_t eidlen; - /* encoding pdu length */ - u16_t pdulen; - /* encoding community length */ - u16_t comlen; - /* encoding version length */ - u16_t verlen; - /* encoding sequence length */ - u16_t seqlen; -}; - -/* Accepting new SNMP messages. */ -#define SNMP_MSG_EMPTY 0 -/* Search for matching object for variable binding. */ -#define SNMP_MSG_SEARCH_OBJ 1 -/* Perform SNMP operation on in-memory object. - Pass-through states, for symmetry only. */ -#define SNMP_MSG_INTERNAL_GET_OBJDEF 2 -#define SNMP_MSG_INTERNAL_GET_VALUE 3 -#define SNMP_MSG_INTERNAL_SET_TEST 4 -#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5 -#define SNMP_MSG_INTERNAL_SET_VALUE 6 -/* Perform SNMP operation on object located externally. - In theory this could be used for building a proxy agent. - Practical use is for an enterprise spc. app. gateway. */ -#define SNMP_MSG_EXTERNAL_GET_OBJDEF 7 -#define SNMP_MSG_EXTERNAL_GET_VALUE 8 -#define SNMP_MSG_EXTERNAL_SET_TEST 9 -#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10 -#define SNMP_MSG_EXTERNAL_SET_VALUE 11 - -#define SNMP_COMMUNITY_STR_LEN 64 -struct snmp_msg_pstat -{ - /* lwIP local port (161) binding */ - struct udp_pcb *pcb; - /* source IP address */ - ip_addr_t sip; - /* source UDP port */ - u16_t sp; - /* request type */ - u8_t rt; - /* request ID */ - s32_t rid; - /* error status */ - s32_t error_status; - /* error index */ - s32_t error_index; - /* community name (zero terminated) */ - u8_t community[SNMP_COMMUNITY_STR_LEN + 1]; - /* community string length (exclusive zero term) */ - u8_t com_strlen; - /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */ - u8_t state; - /* saved arguments for MSG_EXTERNAL_x */ - struct mib_external_node *ext_mib_node; - struct snmp_name_ptr ext_name_ptr; - struct obj_def ext_object_def; - struct snmp_obj_id ext_oid; - /* index into input variable binding list */ - u8_t vb_idx; - /* ptr into input variable binding list */ - struct snmp_varbind *vb_ptr; - /* list of variable bindings from input */ - struct snmp_varbind_root invb; - /* list of variable bindings to output */ - struct snmp_varbind_root outvb; - /* output response lengths used in ASN encoding */ - struct snmp_resp_header_lengths rhl; -}; - -struct snmp_msg_trap -{ - /* lwIP local port (161) binding */ - struct udp_pcb *pcb; - /* destination IP address in network order */ - ip_addr_t dip; - - /* source enterprise ID (sysObjectID) */ - struct snmp_obj_id *enterprise; - /* source IP address, raw network order format */ - u8_t sip_raw[4]; - /* generic trap code */ - u32_t gen_trap; - /* specific trap code */ - u32_t spc_trap; - /* timestamp */ - u32_t ts; - /* list of variable bindings to output */ - struct snmp_varbind_root outvb; - /* output trap lengths used in ASN encoding */ - struct snmp_trap_header_lengths thl; -}; - -/** Agent Version constant, 0 = v1 oddity */ -extern const s32_t snmp_version; -/** Agent default "public" community string */ -extern const char snmp_publiccommunity[7]; - -extern struct snmp_msg_trap trap_msg; - -/** Agent setup, start listening to port 161. */ -void snmp_init(void); -void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable); -void snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst); - -/** Varbind-list functions. */ -struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len); -void snmp_varbind_free(struct snmp_varbind *vb); -void snmp_varbind_list_free(struct snmp_varbind_root *root); -void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb); -struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root); - -/** Handle an internal (recv) or external (private response) event. */ -void snmp_msg_event(u8_t request_id); -err_t snmp_send_response(struct snmp_msg_pstat *m_stat); -err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap); -void snmp_coldstart_trap(void); -void snmp_authfail_trap(void); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SNMP */ - -#endif /* __LWIP_SNMP_MSG_H__ */ diff --git a/tools/sdk/lwip/include/lwip/snmp_structs.h b/tools/sdk/lwip/include/lwip/snmp_structs.h deleted file mode 100644 index 0d3b46a92..000000000 --- a/tools/sdk/lwip/include/lwip/snmp_structs.h +++ /dev/null @@ -1,268 +0,0 @@ -/** - * @file - * Generic MIB tree structures. - * - * @todo namespace prefixes - */ - -/* - * 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 - */ - -#ifndef __LWIP_SNMP_STRUCTS_H__ -#define __LWIP_SNMP_STRUCTS_H__ - -#include "lwip/opt.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/snmp.h" - -#if SNMP_PRIVATE_MIB -/* When using a private MIB, you have to create a file 'private_mib.h' that contains - * a 'struct mib_array_node mib_private' which contains your MIB. */ -#include "private_mib.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* MIB object instance */ -#define MIB_OBJECT_NONE 0 -#define MIB_OBJECT_SCALAR 1 -#define MIB_OBJECT_TAB 2 - -/* MIB access types */ -#define MIB_ACCESS_READ 1 -#define MIB_ACCESS_WRITE 2 - -/* MIB object access */ -#define MIB_OBJECT_READ_ONLY MIB_ACCESS_READ -#define MIB_OBJECT_READ_WRITE (MIB_ACCESS_READ | MIB_ACCESS_WRITE) -#define MIB_OBJECT_WRITE_ONLY MIB_ACCESS_WRITE -#define MIB_OBJECT_NOT_ACCESSIBLE 0 - -/** object definition returned by (get_object_def)() */ -struct obj_def -{ - /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */ - u8_t instance; - /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */ - u8_t access; - /* ASN type for this object */ - u8_t asn_type; - /* value length (host length) */ - u16_t v_len; - /* length of instance part of supplied object identifier */ - u8_t id_inst_len; - /* instance part of supplied object identifier */ - s32_t *id_inst_ptr; -}; - -struct snmp_name_ptr -{ - u8_t ident_len; - s32_t *ident; -}; - -/** MIB const scalar (.0) node */ -#define MIB_NODE_SC 0x01 -/** MIB const array node */ -#define MIB_NODE_AR 0x02 -/** MIB array node (mem_malloced from RAM) */ -#define MIB_NODE_RA 0x03 -/** MIB list root node (mem_malloced from RAM) */ -#define MIB_NODE_LR 0x04 -/** MIB node for external objects */ -#define MIB_NODE_EX 0x05 - -/** node "base class" layout, the mandatory fields for a node */ -struct mib_node -{ - /** returns struct obj_def for the given object identifier */ - void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); - /** returns object value for the given object identifier, - @note the caller must allocate at least len bytes for the value */ - void (*get_value)(struct obj_def *od, u16_t len, void *value); - /** tests length and/or range BEFORE setting */ - u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); - /** sets object value, only to be called when set_test() */ - void (*set_value)(struct obj_def *od, u16_t len, void *value); - /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */ - u8_t node_type; - /* array or max list length */ - u16_t maxlength; -}; - -/** derived node for scalars .0 index */ -typedef struct mib_node mib_scalar_node; - -/** derived node, points to a fixed size const array - of sub-identifiers plus a 'child' pointer */ -struct mib_array_node -{ - /* inherited "base class" members */ - void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); - void (*get_value)(struct obj_def *od, u16_t len, void *value); - u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); - void (*set_value)(struct obj_def *od, u16_t len, void *value); - - u8_t node_type; - u16_t maxlength; - - /* additional struct members */ - const s32_t *objid; - struct mib_node* const *nptr; -}; - -/** derived node, points to a fixed size mem_malloced array - of sub-identifiers plus a 'child' pointer */ -struct mib_ram_array_node -{ - /* inherited "base class" members */ - void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); - void (*get_value)(struct obj_def *od, u16_t len, void *value); - u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); - void (*set_value)(struct obj_def *od, u16_t len, void *value); - - u8_t node_type; - u16_t maxlength; - - /* aditional struct members */ - s32_t *objid; - struct mib_node **nptr; -}; - -struct mib_list_node -{ - struct mib_list_node *prev; - struct mib_list_node *next; - s32_t objid; - struct mib_node *nptr; -}; - -/** derived node, points to a doubly linked list - of sub-identifiers plus a 'child' pointer */ -struct mib_list_rootnode -{ - /* inherited "base class" members */ - void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); - void (*get_value)(struct obj_def *od, u16_t len, void *value); - u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); - void (*set_value)(struct obj_def *od, u16_t len, void *value); - - u8_t node_type; - u16_t maxlength; - - /* additional struct members */ - struct mib_list_node *head; - struct mib_list_node *tail; - /* counts list nodes in list */ - u16_t count; -}; - -/** derived node, has access functions for mib object in external memory or device - using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */ -struct mib_external_node -{ - /* inherited "base class" members */ - void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); - void (*get_value)(struct obj_def *od, u16_t len, void *value); - u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); - void (*set_value)(struct obj_def *od, u16_t len, void *value); - - u8_t node_type; - u16_t maxlength; - - /* additional struct members */ - /** points to an external (in memory) record of some sort of addressing - information, passed to and interpreted by the funtions below */ - void* addr_inf; - /** tree levels under this node */ - u8_t tree_levels; - /** number of objects at this level */ - u16_t (*level_length)(void* addr_inf, u8_t level); - /** compares object sub identifier with external id - return zero when equal, nonzero when unequal */ - s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id); - void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id); - - /** async Questions */ - void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident); - void (*get_value_q)(u8_t rid, struct obj_def *od); - void (*set_test_q)(u8_t rid, struct obj_def *od); - void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value); - /** async Answers */ - void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od); - void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); - u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); - void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); - /** async Panic Close (agent returns error reply, - e.g. used for external transaction cleanup) */ - void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident); - void (*get_value_pc)(u8_t rid, struct obj_def *od); - void (*set_test_pc)(u8_t rid, struct obj_def *od); - void (*set_value_pc)(u8_t rid, struct obj_def *od); -}; - -/** export MIB tree from mib2.c */ -extern const struct mib_array_node internet; - -/** dummy function pointers for non-leaf MIB nodes from mib2.c */ -void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -void noleafs_get_value(struct obj_def *od, u16_t len, void *value); -u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value); -void noleafs_set_value(struct obj_def *od, u16_t len, void *value); - -void snmp_oidtoip(s32_t *ident, ip_addr_t *ip); -void snmp_iptooid(ip_addr_t *ip, s32_t *ident); -void snmp_ifindextonetif(s32_t ifindex, struct netif **netif); -void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx); - -struct mib_list_node* snmp_mib_ln_alloc(s32_t id); -void snmp_mib_ln_free(struct mib_list_node *ln); -struct mib_list_rootnode* snmp_mib_lrn_alloc(void); -void snmp_mib_lrn_free(struct mib_list_rootnode *lrn); - -s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn); -s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn); -struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n); - -struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np); -struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); -u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident); -u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SNMP */ - -#endif /* __LWIP_SNMP_STRUCTS_H__ */ diff --git a/tools/sdk/lwip/include/lwip/sntp.h b/tools/sdk/lwip/include/lwip/sntp.h deleted file mode 100644 index e0d523be1..000000000 --- a/tools/sdk/lwip/include/lwip/sntp.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef LWIP_SNTP_H -#define LWIP_SNTP_H - -#include "lwip/opt.h" -#include "lwip/ip_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef long time_t; - -/** The maximum number of SNTP servers that can be set */ -#ifndef SNTP_MAX_SERVERS -#define SNTP_MAX_SERVERS 3 -#endif - -/** Set this to 1 to implement the callback function called by dhcp when - * NTP servers are received. */ -#ifndef SNTP_GET_SERVERS_FROM_DHCP -#define SNTP_GET_SERVERS_FROM_DHCP 0//LWIP_DHCP_GET_NTP_SRV -#endif - -/* Set this to 1 to support DNS names (or IP address strings) to set sntp servers */ -#ifndef SNTP_SERVER_DNS -#define SNTP_SERVER_DNS 1 -#endif - -bool sntp_get_timetype(void); -void sntp_set_receive_time_size(void); -/** One server address/name can be defined as default if SNTP_SERVER_DNS == 1: - * #define SNTP_SERVER_ADDRESS "pool.ntp.org" - */ -uint32 sntp_get_current_timestamp(); -char* sntp_get_real_time(long t); - -void sntp_init(void); -void sntp_stop(void); - -sint8 sntp_get_timezone(void); -bool sntp_set_timezone(sint8 timezone); -void sntp_setserver(u8_t idx, ip_addr_t *addr); -ip_addr_t sntp_getserver(u8_t idx); - -#if SNTP_SERVER_DNS -void sntp_setservername(u8_t idx, char *server); -char *sntp_getservername(u8_t idx); -#endif /* SNTP_SERVER_DNS */ - -#if SNTP_GET_SERVERS_FROM_DHCP -void sntp_servermode_dhcp(int set_servers_from_dhcp); -#else /* SNTP_GET_SERVERS_FROM_DHCP */ -#define sntp_servermode_dhcp(x) -#endif /* SNTP_GET_SERVERS_FROM_DHCP */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SNTP_H */ diff --git a/tools/sdk/lwip/include/lwip/sockets.h b/tools/sdk/lwip/include/lwip/sockets.h deleted file mode 100644 index 3c8fed24e..000000000 --- a/tools/sdk/lwip/include/lwip/sockets.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - - -#ifndef __LWIP_SOCKETS_H__ -#define __LWIP_SOCKETS_H__ - -#include "lwip/opt.h" - -#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ - -#include /* for size_t */ - -#include "lwip/ip_addr.h" -#include "lwip/inet.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* members are in network byte order */ -struct sockaddr_in { - u8_t sin_len; - u8_t sin_family; - u16_t sin_port; - struct in_addr sin_addr; - char sin_zero[8]; -}; - -struct sockaddr { - u8_t sa_len; - u8_t sa_family; - char sa_data[14]; -}; - -#ifndef socklen_t -# define socklen_t u32_t -#endif - -/* Socket protocol types (TCP/UDP/RAW) */ -#define SOCK_STREAM 1 -#define SOCK_DGRAM 2 -#define SOCK_RAW 3 - -/* - * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) - */ -#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ -#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ -#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ -#define SO_KEEPALIVE 0x0008 /* keep connections alive */ -#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ -#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ -#define SO_LINGER 0x0080 /* linger on close if data present */ -#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ -#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ - -#define SO_DONTLINGER ((int)(~SO_LINGER)) - -/* - * Additional options, not kept in so_options. - */ -#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ -#define SO_RCVBUF 0x1002 /* receive buffer size */ -#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */ -#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */ -#define SO_SNDTIMEO 0x1005 /* Unimplemented: send timeout */ -#define SO_RCVTIMEO 0x1006 /* receive timeout */ -#define SO_ERROR 0x1007 /* get error status and clear */ -#define SO_TYPE 0x1008 /* get socket type */ -#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ -#define SO_NO_CHECK 0x100a /* don't create UDP checksum */ - - -/* - * Structure used for manipulating linger option. - */ -struct linger { - int l_onoff; /* option on/off */ - int l_linger; /* linger time */ -}; - -/* - * Level number for (get/set)sockopt() to apply to socket itself. - */ -#define SOL_SOCKET 0xfff /* options for socket level */ - - -#define AF_UNSPEC 0 -#define AF_INET 2 -#define PF_INET AF_INET -#define PF_UNSPEC AF_UNSPEC - -#define IPPROTO_IP 0 -#define IPPROTO_TCP 6 -#define IPPROTO_UDP 17 -#define IPPROTO_UDPLITE 136 - -/* Flags we can use with send and recv. */ -#define MSG_PEEK 0x01 /* Peeks at an incoming message */ -#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ -#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */ -#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */ -#define MSG_MORE 0x10 /* Sender will send more */ - - -/* - * Options for level IPPROTO_IP - */ -#define IP_TOS 1 -#define IP_TTL 2 - -#if LWIP_TCP -/* - * Options for level IPPROTO_TCP - */ -#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ -#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ -#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ -#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ -#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ -#endif /* LWIP_TCP */ - -#if LWIP_UDP && LWIP_UDPLITE -/* - * Options for level IPPROTO_UDPLITE - */ -#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ -#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ -#endif /* LWIP_UDP && LWIP_UDPLITE*/ - - -#if LWIP_IGMP -/* - * Options and types for UDP multicast traffic handling - */ -#define IP_ADD_MEMBERSHIP 3 -#define IP_DROP_MEMBERSHIP 4 -#define IP_MULTICAST_TTL 5 -#define IP_MULTICAST_IF 6 -#define IP_MULTICAST_LOOP 7 - -typedef struct ip_mreq { - struct in_addr imr_multiaddr; /* IP multicast address of group */ - struct in_addr imr_interface; /* local IP address of interface */ -} ip_mreq; -#endif /* LWIP_IGMP */ - -/* - * The Type of Service provides an indication of the abstract - * parameters of the quality of service desired. These parameters are - * to be used to guide the selection of the actual service parameters - * when transmitting a datagram through a particular network. Several - * networks offer service precedence, which somehow treats high - * precedence traffic as more important than other traffic (generally - * by accepting only traffic above a certain precedence at time of high - * load). The major choice is a three way tradeoff between low-delay, - * high-reliability, and high-throughput. - * The use of the Delay, Throughput, and Reliability indications may - * increase the cost (in some sense) of the service. In many networks - * better performance for one of these parameters is coupled with worse - * performance on another. Except for very unusual cases at most two - * of these three indications should be set. - */ -#define IPTOS_TOS_MASK 0x1E -#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) -#define IPTOS_LOWDELAY 0x10 -#define IPTOS_THROUGHPUT 0x08 -#define IPTOS_RELIABILITY 0x04 -#define IPTOS_LOWCOST 0x02 -#define IPTOS_MINCOST IPTOS_LOWCOST - -/* - * The Network Control precedence designation is intended to be used - * within a network only. The actual use and control of that - * designation is up to each network. The Internetwork Control - * designation is intended for use by gateway control originators only. - * If the actual use of these precedence designations is of concern to - * a particular network, it is the responsibility of that network to - * control the access to, and use of, those precedence designations. - */ -#define IPTOS_PREC_MASK 0xe0 -#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) -#define IPTOS_PREC_NETCONTROL 0xe0 -#define IPTOS_PREC_INTERNETCONTROL 0xc0 -#define IPTOS_PREC_CRITIC_ECP 0xa0 -#define IPTOS_PREC_FLASHOVERRIDE 0x80 -#define IPTOS_PREC_FLASH 0x60 -#define IPTOS_PREC_IMMEDIATE 0x40 -#define IPTOS_PREC_PRIORITY 0x20 -#define IPTOS_PREC_ROUTINE 0x00 - - -/* - * Commands for ioctlsocket(), taken from the BSD file fcntl.h. - * lwip_ioctl only supports FIONREAD and FIONBIO, for now - * - * Ioctl's have the command encoded in the lower word, - * and the size of any in or out parameters in the upper - * word. The high 2 bits of the upper word are used - * to encode the in/out status of the parameter; for now - * we restrict parameters to at most 128 bytes. - */ -#if !defined(FIONREAD) || !defined(FIONBIO) -#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */ -#define IOC_VOID 0x20000000UL /* no parameters */ -#define IOC_OUT 0x40000000UL /* copy out parameters */ -#define IOC_IN 0x80000000UL /* copy in parameters */ -#define IOC_INOUT (IOC_IN|IOC_OUT) - /* 0x20000000 distinguishes new & - old ioctl's */ -#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) - -#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) - -#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) -#endif /* !defined(FIONREAD) || !defined(FIONBIO) */ - -#ifndef FIONREAD -#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ -#endif -#ifndef FIONBIO -#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ -#endif - -/* Socket I/O Controls: unimplemented */ -#ifndef SIOCSHIWAT -#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ -#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ -#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ -#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ -#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ -#endif - -/* commands for fnctl */ -#ifndef F_GETFL -#define F_GETFL 3 -#endif -#ifndef F_SETFL -#define F_SETFL 4 -#endif - -/* File status flags and file access modes for fnctl, - these are bits in an int. */ -#ifndef O_NONBLOCK -#define O_NONBLOCK 1 /* nonblocking I/O */ -#endif -#ifndef O_NDELAY -#define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */ -#endif - -#ifndef SHUT_RD - #define SHUT_RD 0 - #define SHUT_WR 1 - #define SHUT_RDWR 2 -#endif - -/* FD_SET used for lwip_select */ -#ifndef FD_SET - #undef FD_SETSIZE - /* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ - #define FD_SETSIZE MEMP_NUM_NETCONN - #define FD_SET(n, p) ((p)->fd_bits[(n)/8] |= (1 << ((n) & 7))) - #define FD_CLR(n, p) ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7))) - #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] & (1 << ((n) & 7))) - #define FD_ZERO(p) memset((void*)(p),0,sizeof(*(p))) - - typedef struct fd_set { - unsigned char fd_bits [(FD_SETSIZE+7)/8]; - } fd_set; - -#endif /* FD_SET */ - -/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided - * by your system, set this to 0 and include in cc.h */ -#ifndef LWIP_TIMEVAL_PRIVATE -#define LWIP_TIMEVAL_PRIVATE 1 -#endif - -#if LWIP_TIMEVAL_PRIVATE -struct timeval { - long tv_sec; /* seconds */ - long tv_usec; /* and microseconds */ -}; -#endif /* LWIP_TIMEVAL_PRIVATE */ - -void lwip_socket_init(void); - -int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); -int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); -int lwip_shutdown(int s, int how); -int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); -int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); -int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); -int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); -int lwip_close(int s); -int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); -int lwip_listen(int s, int backlog); -int lwip_recv(int s, void *mem, size_t len, int flags); -int lwip_read(int s, void *mem, size_t len); -int lwip_recvfrom(int s, void *mem, size_t len, int flags, - struct sockaddr *from, socklen_t *fromlen); -int lwip_send(int s, const void *dataptr, size_t size, int flags); -int lwip_sendto(int s, const void *dataptr, size_t size, int flags, - const struct sockaddr *to, socklen_t tolen); -int lwip_socket(int domain, int type, int protocol); -int lwip_write(int s, const void *dataptr, size_t size); -int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, - struct timeval *timeout); -int lwip_ioctl(int s, long cmd, void *argp); -int lwip_fcntl(int s, int cmd, int val); - -#if LWIP_COMPAT_SOCKETS -#define accept(a,b,c) lwip_accept(a,b,c) -#define bind(a,b,c) lwip_bind(a,b,c) -#define shutdown(a,b) lwip_shutdown(a,b) -#define closesocket(s) lwip_close(s) -#define connect(a,b,c) lwip_connect(a,b,c) -#define getsockname(a,b,c) lwip_getsockname(a,b,c) -#define getpeername(a,b,c) lwip_getpeername(a,b,c) -#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e) -#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e) -#define listen(a,b) lwip_listen(a,b) -#define recv(a,b,c,d) lwip_recv(a,b,c,d) -#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f) -#define send(a,b,c,d) lwip_send(a,b,c,d) -#define sendto(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f) -#define socket(a,b,c) lwip_socket(a,b,c) -#define select(a,b,c,d,e) lwip_select(a,b,c,d,e) -#define ioctlsocket(a,b,c) lwip_ioctl(a,b,c) - -#if LWIP_POSIX_SOCKETS_IO_NAMES -#define read(a,b,c) lwip_read(a,b,c) -#define write(a,b,c) lwip_write(a,b,c) -#define close(s) lwip_close(s) -#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ - -#endif /* LWIP_COMPAT_SOCKETS */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SOCKET */ - -#endif /* __LWIP_SOCKETS_H__ */ diff --git a/tools/sdk/lwip/include/lwip/stats.h b/tools/sdk/lwip/include/lwip/stats.h deleted file mode 100644 index 43883217e..000000000 --- a/tools/sdk/lwip/include/lwip/stats.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_STATS_H__ -#define __LWIP_STATS_H__ - -#include "lwip/opt.h" - -#include "lwip/mem.h" -#include "lwip/memp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_STATS - -#ifndef LWIP_STATS_LARGE -#define LWIP_STATS_LARGE 0 -#endif - -#if LWIP_STATS_LARGE -#define STAT_COUNTER u32_t -#define STAT_COUNTER_F U32_F -#else -#define STAT_COUNTER u16_t -#define STAT_COUNTER_F U16_F -#endif - -struct stats_proto { - STAT_COUNTER xmit; /* Transmitted packets. */ - STAT_COUNTER recv; /* Received packets. */ - STAT_COUNTER fw; /* Forwarded packets. */ - STAT_COUNTER drop; /* Dropped packets. */ - STAT_COUNTER chkerr; /* Checksum error. */ - STAT_COUNTER lenerr; /* Invalid length error. */ - STAT_COUNTER memerr; /* Out of memory error. */ - STAT_COUNTER rterr; /* Routing error. */ - STAT_COUNTER proterr; /* Protocol error. */ - STAT_COUNTER opterr; /* Error in options. */ - STAT_COUNTER err; /* Misc error. */ - STAT_COUNTER cachehit; -}; - -struct stats_igmp { - STAT_COUNTER xmit; /* Transmitted packets. */ - STAT_COUNTER recv; /* Received packets. */ - STAT_COUNTER drop; /* Dropped packets. */ - STAT_COUNTER chkerr; /* Checksum error. */ - STAT_COUNTER lenerr; /* Invalid length error. */ - STAT_COUNTER memerr; /* Out of memory error. */ - STAT_COUNTER proterr; /* Protocol error. */ - STAT_COUNTER rx_v1; /* Received v1 frames. */ - STAT_COUNTER rx_group; /* Received group-specific queries. */ - STAT_COUNTER rx_general; /* Received general queries. */ - STAT_COUNTER rx_report; /* Received reports. */ - STAT_COUNTER tx_join; /* Sent joins. */ - STAT_COUNTER tx_leave; /* Sent leaves. */ - STAT_COUNTER tx_report; /* Sent reports. */ -}; - -struct stats_mem { -#ifdef LWIP_DEBUG - const char *name; -#endif /* LWIP_DEBUG */ - mem_size_t avail; - mem_size_t used; - mem_size_t max; - STAT_COUNTER err; - STAT_COUNTER illegal; -}; - -struct stats_syselem { - STAT_COUNTER used; - STAT_COUNTER max; - STAT_COUNTER err; -}; - -struct stats_sys { - struct stats_syselem sem; - struct stats_syselem mutex; - struct stats_syselem mbox; -}; - -struct stats_ { -#if LINK_STATS - struct stats_proto link; -#endif -#if ETHARP_STATS - struct stats_proto etharp; -#endif -#if IPFRAG_STATS - struct stats_proto ip_frag; -#endif -#if IP_STATS - struct stats_proto ip; -#endif -#if ICMP_STATS - struct stats_proto icmp; -#endif -#if IGMP_STATS - struct stats_igmp igmp; -#endif -#if UDP_STATS - struct stats_proto udp; -#endif -#if TCP_STATS - struct stats_proto tcp; -#endif -#if MEM_STATS - struct stats_mem mem; -#endif -#if MEMP_STATS - struct stats_mem memp[MEMP_MAX]; -#endif -#if SYS_STATS - struct stats_sys sys; -#endif -}; - -extern struct stats_ lwip_stats; - -void stats_init(void)ICACHE_FLASH_ATTR; - -#define STATS_INC(x) ++lwip_stats.x -#define STATS_DEC(x) --lwip_stats.x -#define STATS_INC_USED(x, y) do { lwip_stats.x.used += y; \ - if (lwip_stats.x.max < lwip_stats.x.used) { \ - lwip_stats.x.max = lwip_stats.x.used; \ - } \ - } while(0) -#else /* LWIP_STATS */ -#define stats_init() -#define STATS_INC(x) -#define STATS_DEC(x) -#define STATS_INC_USED(x) -#endif /* LWIP_STATS */ - -#if TCP_STATS -#define TCP_STATS_INC(x) STATS_INC(x) -#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP") -#else -#define TCP_STATS_INC(x) -#define TCP_STATS_DISPLAY() -#endif - -#if UDP_STATS -#define UDP_STATS_INC(x) STATS_INC(x) -#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP") -#else -#define UDP_STATS_INC(x) -#define UDP_STATS_DISPLAY() -#endif - -#if ICMP_STATS -#define ICMP_STATS_INC(x) STATS_INC(x) -#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP") -#else -#define ICMP_STATS_INC(x) -#define ICMP_STATS_DISPLAY() -#endif - -#if IGMP_STATS -#define IGMP_STATS_INC(x) STATS_INC(x) -#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp) -#else -#define IGMP_STATS_INC(x) -#define IGMP_STATS_DISPLAY() -#endif - -#if IP_STATS -#define IP_STATS_INC(x) STATS_INC(x) -#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP") -#else -#define IP_STATS_INC(x) -#define IP_STATS_DISPLAY() -#endif - -#if IPFRAG_STATS -#define IPFRAG_STATS_INC(x) STATS_INC(x) -#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG") -#else -#define IPFRAG_STATS_INC(x) -#define IPFRAG_STATS_DISPLAY() -#endif - -#if ETHARP_STATS -#define ETHARP_STATS_INC(x) STATS_INC(x) -#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP") -#else -#define ETHARP_STATS_INC(x) -#define ETHARP_STATS_DISPLAY() -#endif - -#if LINK_STATS -#define LINK_STATS_INC(x) STATS_INC(x) -#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK") -#else -#define LINK_STATS_INC(x) -#define LINK_STATS_DISPLAY() -#endif - -#if MEM_STATS -#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y -#define MEM_STATS_INC(x) STATS_INC(mem.x) -#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y) -#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y -#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") -#else -#define MEM_STATS_AVAIL(x, y) -#define MEM_STATS_INC(x) -#define MEM_STATS_INC_USED(x, y) -#define MEM_STATS_DEC_USED(x, y) -#define MEM_STATS_DISPLAY() -#endif - -#if MEMP_STATS -#define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y -#define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x) -#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x) -#define MEMP_STATS_INC_USED(x, i) STATS_INC_USED(memp[i], 1) -#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i) -#else -#define MEMP_STATS_AVAIL(x, i, y) -#define MEMP_STATS_INC(x, i) -#define MEMP_STATS_DEC(x, i) -#define MEMP_STATS_INC_USED(x, i) -#define MEMP_STATS_DISPLAY(i) -#endif - -#if SYS_STATS -#define SYS_STATS_INC(x) STATS_INC(sys.x) -#define SYS_STATS_DEC(x) STATS_DEC(sys.x) -#define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1) -#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys) -#else -#define SYS_STATS_INC(x) -#define SYS_STATS_DEC(x) -#define SYS_STATS_INC_USED(x) -#define SYS_STATS_DISPLAY() -#endif - -/* Display of statistics */ -#if LWIP_STATS_DISPLAY -void stats_display(void)ICACHE_FLASH_ATTR; -void stats_display_proto(struct stats_proto *proto, char *name)ICACHE_FLASH_ATTR; -void stats_display_igmp(struct stats_igmp *igmp)ICACHE_FLASH_ATTR; -void stats_display_mem(struct stats_mem *mem, char *name)ICACHE_FLASH_ATTR; -void stats_display_memp(struct stats_mem *mem, int index)ICACHE_FLASH_ATTR; -void stats_display_sys(struct stats_sys *sys)ICACHE_FLASH_ATTR; -#else /* LWIP_STATS_DISPLAY */ -#define stats_display() -#define stats_display_proto(proto, name) -#define stats_display_igmp(igmp) -#define stats_display_mem(mem, name) -#define stats_display_memp(mem, index) -#define stats_display_sys(sys) -#endif /* LWIP_STATS_DISPLAY */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_STATS_H__ */ diff --git a/tools/sdk/lwip/include/lwip/sys.h b/tools/sdk/lwip/include/lwip/sys.h deleted file mode 100644 index 31a9dea74..000000000 --- a/tools/sdk/lwip/include/lwip/sys.h +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_SYS_H__ -#define __LWIP_SYS_H__ - -#include "lwip/opt.h" - -#include "eagle_soc.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if NO_SYS - -/* For a totally minimal and standalone system, we provide null - definitions of the sys_ functions. */ -typedef u8_t sys_sem_t; -typedef u8_t sys_mutex_t; -typedef u8_t sys_mbox_t; - -#define sys_sem_new(s, c) ERR_OK -#define sys_sem_signal(s) -#define sys_sem_wait(s) -#define sys_arch_sem_wait(s,t) -#define sys_sem_free(s) -#define sys_mutex_new(mu) ERR_OK -#define sys_mutex_lock(mu) -#define sys_mutex_unlock(mu) -#define sys_mutex_free(mu) -#define sys_mbox_new(m, s) ERR_OK -#define sys_mbox_fetch(m,d) -#define sys_mbox_tryfetch(m,d) -#define sys_mbox_post(m,d) -#define sys_mbox_trypost(m,d) -#define sys_mbox_free(m) - -#define sys_thread_new(n,t,a,s,p) - -#define sys_msleep(t) - -#else /* NO_SYS */ - -/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ -#define SYS_ARCH_TIMEOUT 0xffffffffUL - -/** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate. - * For now we use the same magic value, but we allow this to change in future. - */ -#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT - -#include "lwip/err.h" -#include "arch/sys_arch.h" - -/** Function prototype for thread functions */ -typedef void (*lwip_thread_fn)(void *arg); - -/* Function prototypes for functions to be implemented by platform ports - (in sys_arch.c) */ - -/* Mutex functions: */ - -/** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores - should be used instead */ -#if LWIP_COMPAT_MUTEX -/* for old ports that don't have mutexes: define them to binary semaphores */ -#define sys_mutex_t sys_sem_t -#define sys_mutex_new(mutex) sys_sem_new(mutex, 1) -#define sys_mutex_lock(mutex) sys_sem_wait(mutex) -#define sys_mutex_unlock(mutex) sys_sem_signal(mutex) -#define sys_mutex_free(mutex) sys_sem_free(mutex) -#define sys_mutex_valid(mutex) sys_sem_valid(mutex) -#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex) - -#else /* LWIP_COMPAT_MUTEX */ - -/** Create a new mutex - * @param mutex pointer to the mutex to create - * @return a new mutex */ -err_t sys_mutex_new(sys_mutex_t *mutex); -/** Lock a mutex - * @param mutex the mutex to lock */ -void sys_mutex_lock(sys_mutex_t *mutex); -/** Unlock a mutex - * @param mutex the mutex to unlock */ -void sys_mutex_unlock(sys_mutex_t *mutex); -/** Delete a semaphore - * @param mutex the mutex to delete */ -void sys_mutex_free(sys_mutex_t *mutex); -#ifndef sys_mutex_valid -/** Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid */ -int sys_mutex_valid(sys_mutex_t *mutex); -#endif -#ifndef sys_mutex_set_invalid -/** Set a mutex invalid so that sys_mutex_valid returns 0 */ -void sys_mutex_set_invalid(sys_mutex_t *mutex); -#endif -#endif /* LWIP_COMPAT_MUTEX */ - -/* Semaphore functions: */ - -/** Create a new semaphore - * @param sem pointer to the semaphore to create - * @param count initial count of the semaphore - * @return ERR_OK if successful, another err_t otherwise */ -err_t sys_sem_new(sys_sem_t *sem, u8_t count); -/** Signals a semaphore - * @param sem the semaphore to signal */ -void sys_sem_signal(sys_sem_t *sem); -/** Wait for a semaphore for the specified timeout - * @param sem the semaphore to wait for - * @param timeout timeout in milliseconds to wait (0 = wait forever) - * @return time (in milliseconds) waited for the semaphore - * or SYS_ARCH_TIMEOUT on timeout */ -u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout); -/** Delete a semaphore - * @param sem semaphore to delete */ -void sys_sem_free(sys_sem_t *sem); -/** Wait for a semaphore - forever/no timeout */ -#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0) -#ifndef sys_sem_valid -/** Check if a sempahore is valid/allocated: return 1 for valid, 0 for invalid */ -int sys_sem_valid(sys_sem_t *sem); -#endif -#ifndef sys_sem_set_invalid -/** Set a semaphore invalid so that sys_sem_valid returns 0 */ -void sys_sem_set_invalid(sys_sem_t *sem); -#endif - -/* Time functions. */ -#ifndef sys_msleep -void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */ -#endif - -/* Mailbox functions. */ - -/** Create a new mbox of specified size - * @param mbox pointer to the mbox to create - * @param size (miminum) number of messages in this mbox - * @return ERR_OK if successful, another err_t otherwise */ -err_t sys_mbox_new(sys_mbox_t *mbox, int size); -/** Post a message to an mbox - may not fail - * -> blocks if full, only used from tasks not from ISR - * @param mbox mbox to posts the message - * @param msg message to post (ATTENTION: can be NULL) */ -void sys_mbox_post(sys_mbox_t *mbox, void *msg); -/** Try to post a message to an mbox - may fail if full or ISR - * @param mbox mbox to posts the message - * @param msg message to post (ATTENTION: can be NULL) */ -err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg); -/** Wait for a new message to arrive in the mbox - * @param mbox mbox to get a message from - * @param msg pointer where the message is stored - * @param timeout maximum time (in milliseconds) to wait for a message - * @return time (in milliseconds) waited for a message, may be 0 if not waited - or SYS_ARCH_TIMEOUT on timeout - * The returned time has to be accurate to prevent timer jitter! */ -u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout); -/* Allow port to override with a macro, e.g. special timout for sys_arch_mbox_fetch() */ -#ifndef sys_arch_mbox_tryfetch -/** Wait for a new message to arrive in the mbox - * @param mbox mbox to get a message from - * @param msg pointer where the message is stored - * @param timeout maximum time (in milliseconds) to wait for a message - * @return 0 (milliseconds) if a message has been received - * or SYS_MBOX_EMPTY if the mailbox is empty */ -u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg); -#endif -/** For now, we map straight to sys_arch implementation. */ -#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg) -/** Delete an mbox - * @param mbox mbox to delete */ -void sys_mbox_free(sys_mbox_t *mbox); -#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0) -#ifndef sys_mbox_valid -/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */ -int sys_mbox_valid(sys_mbox_t *mbox); -#endif -#ifndef sys_mbox_set_invalid -/** Set an mbox invalid so that sys_mbox_valid returns 0 */ -void sys_mbox_set_invalid(sys_mbox_t *mbox); -#endif - -/** The only thread function: - * Creates a new thread - * @param name human-readable name for the thread (used for debugging purposes) - * @param thread thread-function - * @param arg parameter passed to 'thread' - * @param stacksize stack size in bytes for the new thread (may be ignored by ports) - * @param prio priority of the new thread (may be ignored by ports) */ -sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio); - -#endif /* NO_SYS */ - -/* sys_init() must be called before anthing else. */ -void sys_init(void)ICACHE_FLASH_ATTR; - -#ifndef sys_jiffies -/** Ticks/jiffies since power up. */ -u32_t sys_jiffies(void)ICACHE_FLASH_ATTR; -#endif - -/** Returns the current time in milliseconds, - * may be the same as sys_jiffies or at least based on it. */ -static inline u32_t sys_now(void) ICACHE_FLASH_ATTR; -static inline u32_t sys_now(void) -{ - return NOW()/(TIMER_CLK_FREQ/1000); -} - -/* Critical Region Protection */ -/* These functions must be implemented in the sys_arch.c file. - In some implementations they can provide a more light-weight protection - mechanism than using semaphores. Otherwise semaphores can be used for - implementation */ -#ifndef SYS_ARCH_PROTECT -/** SYS_LIGHTWEIGHT_PROT - * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection - * for certain critical regions during buffer allocation, deallocation and memory - * allocation and deallocation. - */ -#if SYS_LIGHTWEIGHT_PROT - -/** SYS_ARCH_DECL_PROTECT - * declare a protection variable. This macro will default to defining a variable of - * type sys_prot_t. If a particular port needs a different implementation, then - * this macro may be defined in sys_arch.h. - */ -#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev -/** SYS_ARCH_PROTECT - * Perform a "fast" protect. This could be implemented by - * disabling interrupts for an embedded system or by using a semaphore or - * mutex. The implementation should allow calling SYS_ARCH_PROTECT when - * already protected. The old protection level is returned in the variable - * "lev". This macro will default to calling the sys_arch_protect() function - * which should be implemented in sys_arch.c. If a particular port needs a - * different implementation, then this macro may be defined in sys_arch.h - */ -#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() -/** SYS_ARCH_UNPROTECT - * Perform a "fast" set of the protection level to "lev". This could be - * implemented by setting the interrupt level to "lev" within the MACRO or by - * using a semaphore or mutex. This macro will default to calling the - * sys_arch_unprotect() function which should be implemented in - * sys_arch.c. If a particular port needs a different implementation, then - * this macro may be defined in sys_arch.h - */ -#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) -sys_prot_t sys_arch_protect(void)ICACHE_FLASH_ATTR; -void sys_arch_unprotect(sys_prot_t pval)ICACHE_FLASH_ATTR; - -#else - -#define SYS_ARCH_DECL_PROTECT(lev) -#define SYS_ARCH_PROTECT(lev) lev = os_intr_lock() //fix by ives at 2014.3.24 -#define SYS_ARCH_UNPROTECT(lev) lev = os_intr_unlock() - -#endif /* SYS_LIGHTWEIGHT_PROT */ - -#endif /* SYS_ARCH_PROTECT */ - -/* - * Macros to set/get and increase/decrease variables in a thread-safe way. - * Use these for accessing variable that are used from more than one thread. - */ - -#ifndef SYS_ARCH_INC -#define SYS_ARCH_INC(var, val) do { \ - SYS_ARCH_DECL_PROTECT(old_level); \ - SYS_ARCH_PROTECT(old_level); \ - var += val; \ - SYS_ARCH_UNPROTECT(old_level); \ - } while(0) -#endif /* SYS_ARCH_INC */ - -#ifndef SYS_ARCH_DEC -#define SYS_ARCH_DEC(var, val) do { \ - SYS_ARCH_DECL_PROTECT(old_level); \ - SYS_ARCH_PROTECT(old_level); \ - var -= val; \ - SYS_ARCH_UNPROTECT(old_level); \ - } while(0) -#endif /* SYS_ARCH_DEC */ - -#ifndef SYS_ARCH_GET -#define SYS_ARCH_GET(var, ret) do { \ - SYS_ARCH_DECL_PROTECT(old_level); \ - SYS_ARCH_PROTECT(old_level); \ - ret = var; \ - SYS_ARCH_UNPROTECT(old_level); \ - } while(0) -#endif /* SYS_ARCH_GET */ - -#ifndef SYS_ARCH_SET -#define SYS_ARCH_SET(var, val) do { \ - SYS_ARCH_DECL_PROTECT(old_level); \ - SYS_ARCH_PROTECT(old_level); \ - var = val; \ - SYS_ARCH_UNPROTECT(old_level); \ - } while(0) -#endif /* SYS_ARCH_SET */ - - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_SYS_H__ */ diff --git a/tools/sdk/lwip/include/lwip/tcp.h b/tools/sdk/lwip/include/lwip/tcp.h deleted file mode 100644 index 909ff9b70..000000000 --- a/tools/sdk/lwip/include/lwip/tcp.h +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_TCP_H__ -#define __LWIP_TCP_H__ - -#include "lwip/opt.h" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/sys.h" -#include "lwip/mem.h" -#include "lwip/pbuf.h" -#include "lwip/ip.h" -#include "lwip/icmp.h" -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct tcp_pcb; - -/** Function prototype for tcp accept callback functions. Called when a new - * connection can be accepted on a listening pcb. - * - * @param arg Additional argument to pass to the callback function (@see tcp_arg()) - * @param newpcb The new connection pcb - * @param err An error code if there has been an error accepting. - * Only return ERR_ABRT if you have called tcp_abort from within the - * callback function! - */ -typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err); - -/** Function prototype for tcp receive callback functions. Called when data has - * been received. - * - * @param arg Additional argument to pass to the callback function (@see tcp_arg()) - * @param tpcb The connection pcb which received data - * @param p The received data (or NULL when the connection has been closed!) - * @param err An error code if there has been an error receiving - * Only return ERR_ABRT if you have called tcp_abort from within the - * callback function! - */ -typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb, - struct pbuf *p, err_t err); - -/** Function prototype for tcp sent callback functions. Called when sent data has - * been acknowledged by the remote side. Use it to free corresponding resources. - * This also means that the pcb has now space available to send new data. - * - * @param arg Additional argument to pass to the callback function (@see tcp_arg()) - * @param tpcb The connection pcb for which data has been acknowledged - * @param len The amount of bytes acknowledged - * @return ERR_OK: try to send some data by calling tcp_output - * Only return ERR_ABRT if you have called tcp_abort from within the - * callback function! - */ -typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb, - u16_t len); - -/** Function prototype for tcp poll callback functions. Called periodically as - * specified by @see tcp_poll. - * - * @param arg Additional argument to pass to the callback function (@see tcp_arg()) - * @param tpcb tcp pcb - * @return ERR_OK: try to send some data by calling tcp_output - * Only return ERR_ABRT if you have called tcp_abort from within the - * callback function! - */ -typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb); - -/** Function prototype for tcp error callback functions. Called when the pcb - * receives a RST or is unexpectedly closed for any other reason. - * - * @note The corresponding pcb is already freed when this callback is called! - * - * @param arg Additional argument to pass to the callback function (@see tcp_arg()) - * @param err Error code to indicate why the pcb has been closed - * ERR_ABRT: aborted through tcp_abort or by a TCP timer - * ERR_RST: the connection was reset by the remote host - */ -typedef void (*tcp_err_fn)(void *arg, err_t err); - -/** Function prototype for tcp connected callback functions. Called when a pcb - * is connected to the remote side after initiating a connection attempt by - * calling tcp_connect(). - * - * @param arg Additional argument to pass to the callback function (@see tcp_arg()) - * @param tpcb The connection pcb which is connected - * @param err An unused error code, always ERR_OK currently ;-) TODO! - * Only return ERR_ABRT if you have called tcp_abort from within the - * callback function! - * - * @note When a connection attempt fails, the error callback is currently called! - */ -typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err); - -enum tcp_state { - CLOSED = 0, - LISTEN = 1, - SYN_SENT = 2, - SYN_RCVD = 3, - ESTABLISHED = 4, - FIN_WAIT_1 = 5, - FIN_WAIT_2 = 6, - CLOSE_WAIT = 7, - CLOSING = 8, - LAST_ACK = 9, - TIME_WAIT = 10 -}; - -#if LWIP_CALLBACK_API - /* Function to call when a listener has been connected. - * @param arg user-supplied argument (tcp_pcb.callback_arg) - * @param pcb a new tcp_pcb that now is connected - * @param err an error argument (TODO: that is current always ERR_OK?) - * @return ERR_OK: accept the new connection, - * any other err_t abortsthe new connection - */ -#define DEF_ACCEPT_CALLBACK tcp_accept_fn accept; -#else /* LWIP_CALLBACK_API */ -#define DEF_ACCEPT_CALLBACK -#endif /* LWIP_CALLBACK_API */ - -/** - * members common to struct tcp_pcb and struct tcp_listen_pcb - */ -#define TCP_PCB_COMMON(type) \ - type *next; /* for the linked list */ \ - enum tcp_state state; /* TCP state */ \ - u8_t prio; \ - void *callback_arg; \ - /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \ - DEF_ACCEPT_CALLBACK \ - /* ports are in host byte order */ \ - u16_t local_port - - -/* the TCP protocol control block */ -struct tcp_pcb { -/** common PCB members */ - IP_PCB; -/** protocol specific PCB members */ - TCP_PCB_COMMON(struct tcp_pcb); - - /* ports are in host byte order */ - u16_t remote_port; - - u8_t flags; -#define TF_ACK_DELAY ((u8_t)0x01U) /* Delayed ACK. */ -#define TF_ACK_NOW ((u8_t)0x02U) /* Immediate ACK. */ -#define TF_INFR ((u8_t)0x04U) /* In fast recovery. */ -#define TF_TIMESTAMP ((u8_t)0x08U) /* Timestamp option enabled */ -#define TF_RXCLOSED ((u8_t)0x10U) /* rx closed by tcp_shutdown */ -#define TF_FIN ((u8_t)0x20U) /* Connection was closed locally (FIN segment enqueued). */ -#define TF_NODELAY ((u8_t)0x40U) /* Disable Nagle algorithm */ -#define TF_NAGLEMEMERR ((u8_t)0x80U) /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ - - /* the rest of the fields are in host byte order - as we have to do some math with them */ - /* receiver variables */ - u32_t rcv_nxt; /* next seqno expected */ - u16_t rcv_wnd; /* receiver window available */ - u16_t rcv_ann_wnd; /* receiver window to announce */ - u32_t rcv_ann_right_edge; /* announced right edge of window */ - - /* Timers */ - u32_t tmr; - u8_t polltmr, pollinterval; - - /* Retransmission timer. */ - s16_t rtime; - - u16_t mss; /* maximum segment size */ - - /* RTT (round trip time) estimation variables */ - u32_t rttest; /* RTT estimate in 500ms ticks */ - u32_t rtseq; /* sequence number being timed */ - s16_t sa, sv; /* @todo document this */ - - s16_t rto; /* retransmission time-out */ - u8_t nrtx; /* number of retransmissions */ - - /* fast retransmit/recovery */ - u32_t lastack; /* Highest acknowledged seqno. */ - u8_t dupacks; - - /* congestion avoidance/control variables */ - u16_t cwnd; - u16_t ssthresh; - - /* sender variables */ - u32_t snd_nxt; /* next new seqno to be sent */ - u16_t snd_wnd; /* sender window */ - u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last - window update. */ - u32_t snd_lbb; /* Sequence number of next byte to be buffered. */ - - u16_t acked; - - u16_t snd_buf; /* Available buffer space for sending (in bytes). */ -#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3) - u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */ - -#if TCP_OVERSIZE - /* Extra bytes available at the end of the last pbuf in unsent. */ - u16_t unsent_oversize; -#endif /* TCP_OVERSIZE */ - - /* These are ordered by sequence number: */ - struct tcp_seg *unsent; /* Unsent (queued) segments. */ - struct tcp_seg *unacked; /* Sent but unacknowledged segments. */ -#if TCP_QUEUE_OOSEQ - struct tcp_seg *ooseq; /* Received out of sequence segments. */ -#endif /* TCP_QUEUE_OOSEQ */ - - struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ - -#if LWIP_CALLBACK_API - /* Function to be called when more send buffer space is available. */ - tcp_sent_fn sent; - /* Function to be called when (in-sequence) data has arrived. */ - tcp_recv_fn recv; - /* Function to be called when a connection has been set up. */ - tcp_connected_fn connected; - /* Function which is called periodically. */ - tcp_poll_fn poll; - /* Function to be called whenever a fatal error occurs. */ - tcp_err_fn errf; -#endif /* LWIP_CALLBACK_API */ - -#if LWIP_TCP_TIMESTAMPS - u32_t ts_lastacksent; - u32_t ts_recent; -#endif /* LWIP_TCP_TIMESTAMPS */ - - /* idle time before KEEPALIVE is sent */ - u32_t keep_idle; -#if LWIP_TCP_KEEPALIVE - u32_t keep_intvl; - u32_t keep_cnt; -#endif /* LWIP_TCP_KEEPALIVE */ - - /* Persist timer counter */ - u32_t persist_cnt; - /* Persist timer back-off */ - u8_t persist_backoff; - - /* KEEPALIVE counter */ - u8_t keep_cnt_sent; -}; - -struct tcp_pcb_listen { -/* Common members of all PCB types */ - IP_PCB; -/* Protocol specific PCB members */ - TCP_PCB_COMMON(struct tcp_pcb_listen); - -#if TCP_LISTEN_BACKLOG - u8_t backlog; - u8_t accepts_pending; -#endif /* TCP_LISTEN_BACKLOG */ -}; - -#if LWIP_EVENT_API - -enum lwip_event { - LWIP_EVENT_ACCEPT, - LWIP_EVENT_SENT, - LWIP_EVENT_RECV, - LWIP_EVENT_CONNECTED, - LWIP_EVENT_POLL, - LWIP_EVENT_ERR -}; - -err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, - enum lwip_event, - struct pbuf *p, - u16_t size, - err_t err); - -#endif /* LWIP_EVENT_API */ - -/* Application program's interface: */ -struct tcp_pcb * tcp_new (void)ICACHE_FLASH_ATTR; - -void tcp_arg (struct tcp_pcb *pcb, void *arg) ICACHE_FLASH_ATTR; -void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept) ICACHE_FLASH_ATTR; -void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv) ICACHE_FLASH_ATTR; -void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent)ICACHE_FLASH_ATTR; -void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)ICACHE_FLASH_ATTR; -void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err)ICACHE_FLASH_ATTR; - -#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) -#define tcp_sndbuf(pcb) ((pcb)->snd_buf) -#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen) -#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY) -#define tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY) -#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0) - -#if TCP_LISTEN_BACKLOG -#define tcp_accepted(pcb) do { \ - LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", pcb->state == LISTEN); \ - (((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0) -#else /* TCP_LISTEN_BACKLOG */ -#define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \ - pcb->state == LISTEN) -#endif /* TCP_LISTEN_BACKLOG */ - -void tcp_recved (struct tcp_pcb *pcb, u16_t len)ICACHE_FLASH_ATTR; -err_t tcp_bind (struct tcp_pcb *pcb, ip_addr_t *ipaddr, - u16_t port)ICACHE_FLASH_ATTR; -err_t tcp_connect (struct tcp_pcb *pcb, ip_addr_t *ipaddr, - u16_t port, tcp_connected_fn connected)ICACHE_FLASH_ATTR; - -struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)ICACHE_FLASH_ATTR; -#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) - -void tcp_abort (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; -err_t tcp_close (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; -err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)ICACHE_FLASH_ATTR; - -/* Flags for "apiflags" parameter in tcp_write */ -#define TCP_WRITE_FLAG_COPY 0x01 -#define TCP_WRITE_FLAG_MORE 0x02 - -err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, - u8_t apiflags)ICACHE_FLASH_ATTR; - -void tcp_setprio (struct tcp_pcb *pcb, u8_t prio)ICACHE_FLASH_ATTR; - -#define TCP_PRIO_MIN 1 -#define TCP_PRIO_NORMAL 64 -#define TCP_PRIO_MAX 127 - -extern err_t tcp_output(struct tcp_pcb *pcb); - - -const char* tcp_debug_state_str(enum tcp_state s)ICACHE_FLASH_ATTR; - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_TCP */ - -#endif /* __LWIP_TCP_H__ */ diff --git a/tools/sdk/lwip/include/lwip/tcp_impl.h b/tools/sdk/lwip/include/lwip/tcp_impl.h deleted file mode 100644 index f6778700a..000000000 --- a/tools/sdk/lwip/include/lwip/tcp_impl.h +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_TCP_IMPL_H__ -#define __LWIP_TCP_IMPL_H__ - -#include "lwip/opt.h" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/tcp.h" -#include "lwip/sys.h" -#include "lwip/mem.h" -#include "lwip/pbuf.h" -#include "lwip/ip.h" -#include "lwip/icmp.h" -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Functions for interfacing with TCP: */ - -/* Lower layer interface to TCP: */ -#define tcp_init() /* Compatibility define, no init needed. */ -void tcp_tmr (void)ICACHE_FLASH_ATTR; /* Must be called every - TCP_TMR_INTERVAL - ms. (Typically 250 ms). */ -/* It is also possible to call these two functions at the right - intervals (instead of calling tcp_tmr()). */ -void tcp_slowtmr (void)ICACHE_FLASH_ATTR; -void tcp_fasttmr (void)ICACHE_FLASH_ATTR; - - -/* Only used by IP to pass a TCP segment to TCP: */ -void tcp_input (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; -/* Used within the TCP code only: */ -struct tcp_pcb * tcp_alloc (u8_t prio)ICACHE_FLASH_ATTR; -void tcp_abandon (struct tcp_pcb *pcb, int reset)ICACHE_FLASH_ATTR; -err_t tcp_send_empty_ack(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; -void tcp_rexmit (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; -void tcp_rexmit_rto (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; -void tcp_rexmit_fast (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; -u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; - -/** - * This is the Nagle algorithm: try to combine user data to send as few TCP - * segments as possible. Only send if - * - no previously transmitted data on the connection remains unacknowledged or - * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or - * - the only unsent segment is at least pcb->mss bytes long (or there is more - * than one unsent segment - with lwIP, this can happen although unsent->len < mss) - * - or if we are in fast-retransmit (TF_INFR) - */ -#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ - ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ - (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ - ((tpcb)->unsent->len >= (tpcb)->mss))) \ - ) ? 1 : 0) -#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) - - -#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0) -#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0) -#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0) -#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0) -/* is b<=a<=c? */ -#if 0 /* see bug #10548 */ -#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) -#endif -#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) -#define TCP_FIN 0x01U -#define TCP_SYN 0x02U -#define TCP_RST 0x04U -#define TCP_PSH 0x08U -#define TCP_ACK 0x10U -#define TCP_URG 0x20U -#define TCP_ECE 0x40U -#define TCP_CWR 0x80U - -#define TCP_FLAGS 0x3fU - -/* Length of the TCP header, excluding options. */ -#define TCP_HLEN 20 - -#ifndef TCP_TMR_INTERVAL -#define TCP_TMR_INTERVAL 125 /* The TCP timer interval in milliseconds. */ -#endif /* TCP_TMR_INTERVAL */ - -#ifndef TCP_FAST_INTERVAL -#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ -#endif /* TCP_FAST_INTERVAL */ - -#ifndef TCP_SLOW_INTERVAL -#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */ -#endif /* TCP_SLOW_INTERVAL */ - -#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ -#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ - -#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ - -#ifndef TCP_MSL -#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ -#endif - -/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ -#ifndef TCP_KEEPIDLE_DEFAULT -#define TCP_KEEPIDLE_DEFAULT 120000UL /* Default KEEPALIVE timer in milliseconds */ -#endif - -#ifndef TCP_KEEPINTVL_DEFAULT -#define TCP_KEEPINTVL_DEFAULT 10000UL /* Default Time between KEEPALIVE probes in milliseconds */ -#endif - -#ifndef TCP_KEEPCNT_DEFAULT -#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */ -#endif - -#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */ - -/* Fields are (of course) in network byte order. - * Some fields are converted to host byte order in tcp_input(). - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct tcp_hdr { - PACK_STRUCT_FIELD(u16_t src); //Դ�˿� - PACK_STRUCT_FIELD(u16_t dest); //Ŀ�Ķ˿� - PACK_STRUCT_FIELD(u32_t seqno); //��� - PACK_STRUCT_FIELD(u32_t ackno); //Ӧ����� - PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);//�ײ�����+����λ+��־λ - PACK_STRUCT_FIELD(u16_t wnd); //���ڴ�С - PACK_STRUCT_FIELD(u16_t chksum); //��� - PACK_STRUCT_FIELD(u16_t urgp); //����ָ�� -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8) -#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12) -#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS) - -#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr)) -#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr)) -#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags)) -#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | (flags)) - -#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags)) -#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) ) - -#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0)) - -/** Flags used on input processing, not on pcb->flags -*/ -#define TF_RESET (u8_t)0x08U /* Connection was reset. */ -#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */ -#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ - - -#if LWIP_EVENT_API - -#define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ - LWIP_EVENT_ACCEPT, NULL, 0, err) -#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ - LWIP_EVENT_SENT, NULL, space, ERR_OK) -#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ - LWIP_EVENT_RECV, (p), 0, (err)) -#define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ - LWIP_EVENT_RECV, NULL, 0, ERR_OK) -#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ - LWIP_EVENT_CONNECTED, NULL, 0, (err)) -#define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ - LWIP_EVENT_POLL, NULL, 0, ERR_OK) -#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \ - LWIP_EVENT_ERR, NULL, 0, (err)) - -#else /* LWIP_EVENT_API */ - -#define TCP_EVENT_ACCEPT(pcb,err,ret) \ - do { \ - if((pcb)->accept != NULL) \ - (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \ - else (ret) = ERR_ARG; \ - } while (0) - -#define TCP_EVENT_SENT(pcb,space,ret) \ - do { \ - if((pcb)->sent != NULL) \ - (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \ - else (ret) = ERR_OK; \ - } while (0) - -#define TCP_EVENT_RECV(pcb,p,err,ret) \ - do { \ - if((pcb)->recv != NULL) { \ - (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\ - } else { \ - (ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \ - } \ - } while (0) - -#define TCP_EVENT_CLOSED(pcb,ret) \ - do { \ - if(((pcb)->recv != NULL)) { \ - (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\ - } else { \ - (ret) = ERR_OK; \ - } \ - } while (0) - -#define TCP_EVENT_CONNECTED(pcb,err,ret) \ - do { \ - if((pcb)->connected != NULL) \ - (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ - else (ret) = ERR_OK; \ - } while (0) - -#define TCP_EVENT_POLL(pcb,ret) \ - do { \ - if((pcb)->poll != NULL) \ - (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \ - else (ret) = ERR_OK; \ - } while (0) - -#define TCP_EVENT_ERR(errf,arg,err) \ - do { \ - if((errf) != NULL) \ - (errf)((arg),(err)); \ - } while (0) - -#endif /* LWIP_EVENT_API */ - -/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */ -#if TCP_OVERSIZE && defined(LWIP_DEBUG) -#define TCP_OVERSIZE_DBGCHECK 1 -#else -#define TCP_OVERSIZE_DBGCHECK 0 -#endif - -/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */ -#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP) - -/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */ -struct tcp_seg { - struct tcp_seg *next; /* used when putting segements on a queue */ - struct pbuf *p; /* buffer containing data + TCP header */ - void *dataptr; /* pointer to the TCP data in the pbuf */ - u16_t len; /* the TCP length of this segment */ -#if TCP_OVERSIZE_DBGCHECK - u16_t oversize_left; /* Extra bytes available at the end of the last - pbuf in unsent (used for asserting vs. - tcp_pcb.unsent_oversized only) */ -#endif /* TCP_OVERSIZE_DBGCHECK */ -#if TCP_CHECKSUM_ON_COPY - u16_t chksum; - u8_t chksum_swapped; -#endif /* TCP_CHECKSUM_ON_COPY */ - u8_t flags; -#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ -#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ -#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is - checksummed into 'chksum' */ - struct tcp_hdr *tcphdr; /* the TCP header */ -}; - -#define LWIP_TCP_OPT_LENGTH(flags) \ - (flags & TF_SEG_OPTS_MSS ? 4 : 0) + \ - (flags & TF_SEG_OPTS_TS ? 12 : 0) - -/** This returns a TCP header option for MSS in an u32_t */ -#define TCP_BUILD_MSS_OPTION(x) (x) = PP_HTONL(((u32_t)2 << 24) | \ - ((u32_t)4 << 16) | \ - (((u32_t)TCP_MSS / 256) << 8) | \ - (TCP_MSS & 255)) - -/* Global variables: */ -extern struct tcp_pcb *tcp_input_pcb; -extern u32_t tcp_ticks; - -/* The TCP PCB lists. */ -union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ - struct tcp_pcb_listen *listen_pcbs; - struct tcp_pcb *pcbs; -}; -extern struct tcp_pcb *tcp_bound_pcbs; -extern union tcp_listen_pcbs_t tcp_listen_pcbs; -extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a - state in which they accept or send - data. */ -extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ - -extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */ - -/* Axioms about the above lists: - 1) Every TCP PCB that is not CLOSED is in one of the lists. - 2) A PCB is only in one of the lists. - 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. - 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. -*/ -/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB - with a PCB list or removes a PCB from a list, respectively. */ -#ifndef TCP_DEBUG_PCB_LISTS -#define TCP_DEBUG_PCB_LISTS 0 -#endif -#if TCP_DEBUG_PCB_LISTS -#define TCP_REG(pcbs, npcb) do {\ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", (npcb), (npcb)->local_port)); \ - for(tcp_tmp_pcb = *(pcbs); \ - tcp_tmp_pcb != NULL; \ - tcp_tmp_pcb = tcp_tmp_pcb->next) { \ - LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \ - } \ - LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \ - (npcb)->next = *(pcbs); \ - LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \ - *(pcbs) = (npcb); \ - LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ - tcp_timer_needed(); \ - } while(0) -#define TCP_RMV(pcbs, npcb) do { \ - LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \ - if(*(pcbs) == (npcb)) { \ - *(pcbs) = (*pcbs)->next; \ - } else for(tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ - if(tcp_tmp_pcb->next == (npcb)) { \ - tcp_tmp_pcb->next = (npcb)->next; \ - break; \ - } \ - } \ - (npcb)->next = NULL; \ - LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \ - } while(0) - -#else /* LWIP_DEBUG */ - -#define TCP_REG(pcbs, npcb) \ - do { \ - (npcb)->next = *pcbs; \ - *(pcbs) = (npcb); \ - tcp_timer_needed(); \ - } while (0) - -#define TCP_RMV(pcbs, npcb) \ - do { \ - if(*(pcbs) == (npcb)) { \ - (*(pcbs)) = (*pcbs)->next; \ - } \ - else { \ - for(tcp_tmp_pcb = *pcbs; \ - tcp_tmp_pcb != NULL; \ - tcp_tmp_pcb = tcp_tmp_pcb->next) { \ - if(tcp_tmp_pcb->next == (npcb)) { \ - tcp_tmp_pcb->next = (npcb)->next; \ - break; \ - } \ - } \ - } \ - (npcb)->next = NULL; \ - } while(0) - -#endif /* LWIP_DEBUG */ - -#define TCP_TW_LIMIT(l) \ - do { \ - u32_t tcp_tmp_pcbs_count = 0; \ - tcp_tmp_pcb = tcp_tw_pcbs; \ - while(tcp_tmp_pcb != NULL) { \ - if(++tcp_tmp_pcbs_count == (l)) { \ - struct tcp_pcb *_tcp_tmp_pcb = tcp_tmp_pcb->next; \ - tcp_tmp_pcb->next = NULL; \ - tcp_tmp_pcb = _tcp_tmp_pcb; \ - while(tcp_tmp_pcb != NULL) { \ - _tcp_tmp_pcb = tcp_tmp_pcb; \ - tcp_pcb_purge(tcp_tmp_pcb); \ - tcp_tmp_pcb = tcp_tmp_pcb->next; \ - memp_free(MEMP_TCP_PCB, _tcp_tmp_pcb); \ - } \ - break; \ - } \ - tcp_tmp_pcb = tcp_tmp_pcb->next; \ - } \ - } while(0) - -/* Internal functions: */ -struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; -void tcp_pcb_purge(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; -void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; - -void tcp_segs_free(struct tcp_seg *seg)ICACHE_FLASH_ATTR; -void tcp_seg_free(struct tcp_seg *seg)ICACHE_FLASH_ATTR; -struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg)ICACHE_FLASH_ATTR; - -#define tcp_ack(pcb) \ - do { \ - if((pcb)->flags & TF_ACK_DELAY) { \ - (pcb)->flags &= ~TF_ACK_DELAY; \ - (pcb)->flags |= TF_ACK_NOW; \ - } \ - else { \ - (pcb)->flags |= TF_ACK_DELAY; \ - } \ - } while (0) - -#define tcp_ack_now(pcb) \ - do { \ - (pcb)->flags |= TF_ACK_NOW; \ - } while (0) - -err_t tcp_send_fin(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; -err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)ICACHE_FLASH_ATTR; - -void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg)ICACHE_FLASH_ATTR; - -void tcp_rst(u32_t seqno, u32_t ackno, - ip_addr_t *local_ip, ip_addr_t *remote_ip, - u16_t local_port, u16_t remote_port)ICACHE_FLASH_ATTR; - -u32_t tcp_next_iss(void)ICACHE_FLASH_ATTR; - -void tcp_keepalive(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; -void tcp_zero_window_probe(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; - -#if TCP_CALCULATE_EFF_SEND_MSS -u16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)ICACHE_FLASH_ATTR; -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - -#if LWIP_CALLBACK_API -err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)ICACHE_FLASH_ATTR; -#endif /* LWIP_CALLBACK_API */ - -#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG -void tcp_debug_print(struct tcp_hdr *tcphdr)ICACHE_FLASH_ATTR; -void tcp_debug_print_flags(u8_t flags)ICACHE_FLASH_ATTR; -void tcp_debug_print_state(enum tcp_state s)ICACHE_FLASH_ATTR; -void tcp_debug_print_pcbs(void)ICACHE_FLASH_ATTR; -s16_t tcp_pcbs_sane(void)ICACHE_FLASH_ATTR; -#else -# define tcp_debug_print(tcphdr) -# define tcp_debug_print_flags(flags) -# define tcp_debug_print_state(s) -# define tcp_debug_print_pcbs() -# define tcp_pcbs_sane() 1 -#endif /* TCP_DEBUG */ - -/** External function (implemented in timers.c), called when TCP detects - * that a timer is needed (i.e. active- or time-wait-pcb found). */ -void tcp_timer_needed(void)ICACHE_FLASH_ATTR; - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_TCP */ - -#endif /* __LWIP_TCP_H__ */ diff --git a/tools/sdk/lwip/include/lwip/tcpip.h b/tools/sdk/lwip/include/lwip/tcpip.h deleted file mode 100644 index 995ba8ad0..000000000 --- a/tools/sdk/lwip/include/lwip/tcpip.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_TCPIP_H__ -#define __LWIP_TCPIP_H__ - -#include "lwip/opt.h" - -#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/api_msg.h" -#include "lwip/netifapi.h" -#include "lwip/pbuf.h" -#include "lwip/api.h" -#include "lwip/sys.h" -#include "lwip/timers.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Define this to something that triggers a watchdog. This is called from - * tcpip_thread after processing a message. */ -#ifndef LWIP_TCPIP_THREAD_ALIVE -#define LWIP_TCPIP_THREAD_ALIVE() -#endif - -#if LWIP_TCPIP_CORE_LOCKING -/** The global semaphore to lock the stack. */ -extern sys_mutex_t lock_tcpip_core; -#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) -#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core) -#define TCPIP_APIMSG(m) tcpip_apimsg_lock(m) -#define TCPIP_APIMSG_ACK(m) -#define TCPIP_NETIFAPI(m) tcpip_netifapi_lock(m) -#define TCPIP_NETIFAPI_ACK(m) -#else /* LWIP_TCPIP_CORE_LOCKING */ -#define LOCK_TCPIP_CORE() -#define UNLOCK_TCPIP_CORE() -#define TCPIP_APIMSG(m) tcpip_apimsg(m) -#define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed) -#define TCPIP_NETIFAPI(m) tcpip_netifapi(m) -#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem) -#endif /* LWIP_TCPIP_CORE_LOCKING */ - -/** Function prototype for the init_done function passed to tcpip_init */ -typedef void (*tcpip_init_done_fn)(void *arg); -/** Function prototype for functions passed to tcpip_callback() */ -typedef void (*tcpip_callback_fn)(void *ctx); - -void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg); - -#if LWIP_NETCONN -err_t tcpip_apimsg(struct api_msg *apimsg); -#if LWIP_TCPIP_CORE_LOCKING -err_t tcpip_apimsg_lock(struct api_msg *apimsg); -#endif /* LWIP_TCPIP_CORE_LOCKING */ -#endif /* LWIP_NETCONN */ - -err_t tcpip_input(struct pbuf *p, struct netif *inp); - -#if LWIP_NETIF_API -err_t tcpip_netifapi(struct netifapi_msg *netifapimsg); -#if LWIP_TCPIP_CORE_LOCKING -err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg); -#endif /* LWIP_TCPIP_CORE_LOCKING */ -#endif /* LWIP_NETIF_API */ - -err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block); -#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1) - -/* free pbufs or heap memory from another context without blocking */ -err_t pbuf_free_callback(struct pbuf *p); -err_t mem_free_callback(void *m); - -#if LWIP_TCPIP_TIMEOUT -err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); -err_t tcpip_untimeout(sys_timeout_handler h, void *arg); -#endif /* LWIP_TCPIP_TIMEOUT */ - -enum tcpip_msg_type { -#if LWIP_NETCONN - TCPIP_MSG_API, -#endif /* LWIP_NETCONN */ - TCPIP_MSG_INPKT, -#if LWIP_NETIF_API - TCPIP_MSG_NETIFAPI, -#endif /* LWIP_NETIF_API */ -#if LWIP_TCPIP_TIMEOUT - TCPIP_MSG_TIMEOUT, - TCPIP_MSG_UNTIMEOUT, -#endif /* LWIP_TCPIP_TIMEOUT */ - TCPIP_MSG_CALLBACK -}; - -struct tcpip_msg { - enum tcpip_msg_type type; - sys_sem_t *sem; - union { -#if LWIP_NETCONN - struct api_msg *apimsg; -#endif /* LWIP_NETCONN */ -#if LWIP_NETIF_API - struct netifapi_msg *netifapimsg; -#endif /* LWIP_NETIF_API */ - struct { - struct pbuf *p; - struct netif *netif; - } inp; - struct { - tcpip_callback_fn function; - void *ctx; - } cb; -#if LWIP_TCPIP_TIMEOUT - struct { - u32_t msecs; - sys_timeout_handler h; - void *arg; - } tmo; -#endif /* LWIP_TCPIP_TIMEOUT */ - } msg; -}; - -#ifdef __cplusplus -} -#endif - -#endif /* !NO_SYS */ - -#endif /* __LWIP_TCPIP_H__ */ diff --git a/tools/sdk/lwip/include/lwip/timers.h b/tools/sdk/lwip/include/lwip/timers.h deleted file mode 100644 index e9db02a2f..000000000 --- a/tools/sdk/lwip/include/lwip/timers.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * Simon Goldschmidt - * - */ -#ifndef __LWIP_TIMERS_H__ -#define __LWIP_TIMERS_H__ - -#include "lwip/opt.h" - -/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */ -#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) - -#if LWIP_TIMERS - -#include "lwip/err.h" -#include "lwip/sys.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef LWIP_DEBUG_TIMERNAMES -#ifdef LWIP_DEBUG -#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG -#else /* LWIP_DEBUG */ -#define LWIP_DEBUG_TIMERNAMES 0 -#endif /* LWIP_DEBUG*/ -#endif - -/** Function prototype for a timeout callback function. Register such a function - * using sys_timeout(). - * - * @param arg Additional argument to pass to the function - set up by sys_timeout() - */ -typedef void (* sys_timeout_handler)(void *arg); - -struct sys_timeo { - struct sys_timeo *next; - u32_t time; - sys_timeout_handler h; - void *arg; -#if LWIP_DEBUG_TIMERNAMES - const char* handler_name; -#endif /* LWIP_DEBUG_TIMERNAMES */ -}; - -void sys_timeouts_init(void)ICACHE_FLASH_ATTR; - -#if LWIP_DEBUG_TIMERNAMES -void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)ICACHE_FLASH_ATTR; -#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler) -#else /* LWIP_DEBUG_TIMERNAMES */ -void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)ICACHE_FLASH_ATTR; -#endif /* LWIP_DEBUG_TIMERNAMES */ - -void sys_untimeout(sys_timeout_handler handler, void *arg)ICACHE_FLASH_ATTR; -#if NO_SYS -void sys_check_timeouts(void)ICACHE_FLASH_ATTR; -void sys_restart_timeouts(void)ICACHE_FLASH_ATTR; -#else /* NO_SYS */ -void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg); -#endif /* NO_SYS */ - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_TIMERS */ -#endif /* __LWIP_TIMERS_H__ */ diff --git a/tools/sdk/lwip/include/lwip/udp.h b/tools/sdk/lwip/include/lwip/udp.h deleted file mode 100644 index 2e4b57ae7..000000000 --- a/tools/sdk/lwip/include/lwip/udp.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_UDP_H__ -#define __LWIP_UDP_H__ - -#include "lwip/opt.h" - -#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/pbuf.h" -#include "lwip/netif.h" -#include "lwip/ip_addr.h" -#include "lwip/ip.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define UDP_HLEN 8 - -/* Fields are (of course) in network byte order. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct udp_hdr { - PACK_STRUCT_FIELD(u16_t src); - PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ - PACK_STRUCT_FIELD(u16_t len); - PACK_STRUCT_FIELD(u16_t chksum); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define UDP_FLAGS_NOCHKSUM 0x01U -#define UDP_FLAGS_UDPLITE 0x02U -#define UDP_FLAGS_CONNECTED 0x04U -#define UDP_FLAGS_MULTICAST_LOOP 0x08U - -struct udp_pcb; - -/** Function prototype for udp pcb receive callback functions - * addr and port are in same byte order as in the pcb - * The callback is responsible for freeing the pbuf - * if it's not used any more. - * - * ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf - * makes 'addr' invalid, too. - * - * @param arg user supplied argument (udp_pcb.recv_arg) - * @param pcb the udp_pcb which received data - * @param p the packet buffer that was received - * @param addr the remote IP address from which the packet was received - * @param port the remote port from which the packet was received - */ -typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, - ip_addr_t *addr, u16_t port); - - -struct udp_pcb { -/* Common members of all PCB types */ - IP_PCB; - -/* Protocol specific PCB members */ - - struct udp_pcb *next; - - u8_t flags; - /** ports are in host byte order */ - u16_t local_port, remote_port; - -#if LWIP_IGMP - /** outgoing network interface for multicast packets */ - ip_addr_t multicast_ip; -#ifndef LWIP_MAYBE_XCC - /** TTL for outgoing multicast packets */ - u8_t mcast_ttl; -#endif /* LWIP_MAYBE_XCC */ -#endif /* LWIP_IGMP */ - -#if LWIP_UDPLITE - /** used for UDP_LITE only */ - u16_t chksum_len_rx, chksum_len_tx; -#endif /* LWIP_UDPLITE */ - - /** receive callback function */ - udp_recv_fn recv; - /** user-supplied argument for the recv callback */ - void *recv_arg; -}; -/* udp_pcbs export for exernal reference (e.g. SNMP agent) */ -extern struct udp_pcb *udp_pcbs; - -/* The following functions is the application layer interface to the - UDP code. */ -struct udp_pcb * udp_new (void)ICACHE_FLASH_ATTR; -void udp_remove (struct udp_pcb *pcb)ICACHE_FLASH_ATTR; -err_t udp_bind (struct udp_pcb *pcb, ip_addr_t *ipaddr, - u16_t port)ICACHE_FLASH_ATTR; -err_t udp_connect (struct udp_pcb *pcb, ip_addr_t *ipaddr, - u16_t port)ICACHE_FLASH_ATTR; -void udp_disconnect (struct udp_pcb *pcb)ICACHE_FLASH_ATTR; -void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, - void *recv_arg)ICACHE_FLASH_ATTR; -err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, - ip_addr_t *dst_ip, u16_t dst_port, - struct netif *netif)ICACHE_FLASH_ATTR; -err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, - ip_addr_t *dst_ip, u16_t dst_port)ICACHE_FLASH_ATTR; -err_t udp_send (struct udp_pcb *pcb, struct pbuf *p)ICACHE_FLASH_ATTR; - -#if LWIP_CHECKSUM_ON_COPY -err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, - ip_addr_t *dst_ip, u16_t dst_port, - struct netif *netif, u8_t have_chksum, - u16_t chksum)ICACHE_FLASH_ATTR; -err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, - ip_addr_t *dst_ip, u16_t dst_port, - u8_t have_chksum, u16_t chksum)ICACHE_FLASH_ATTR; -err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, - u8_t have_chksum, u16_t chksum)ICACHE_FLASH_ATTR; -#endif /* LWIP_CHECKSUM_ON_COPY */ - -#define udp_flags(pcb) ((pcb)->flags) -#define udp_setflags(pcb, f) ((pcb)->flags = (f)) - -/* The following functions are the lower layer interface to UDP. */ -void udp_input (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; - -#define udp_init() /* Compatibility define, not init needed. */ - -#if LWIP_IGMP -#define udp_set_multicast_netif_addr(pcb, ipaddr) ip_addr_copy((pcb)->multicast_ip, (ipaddr)) -#define udp_get_multicast_netif_addr(pcb) ((pcb)->multicast_ip) -#ifndef LWIP_MAYBE_XCC -#define udp_set_multicast_ttl(pcb, value) do { (pcb)->mcast_ttl = value; } while(0) -#define udp_get_multicast_ttl(pcb) ((pcb)->mcast_ttl) -#endif /* LWIP_MAYBE_XCC */ -#endif /* LWIP_IGMP */ - -#if UDP_DEBUG -void udp_debug_print(struct udp_hdr *udphdr)ICACHE_FLASH_ATTR; -#else -#define udp_debug_print(udphdr) -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_UDP */ - -#endif /* __LWIP_UDP_H__ */ diff --git a/tools/sdk/lwip/include/lwipopts.h b/tools/sdk/lwip/include/lwipopts.h deleted file mode 100644 index 2081b3aea..000000000 --- a/tools/sdk/lwip/include/lwipopts.h +++ /dev/null @@ -1,2078 +0,0 @@ -/** - * @file - * - * lwIP Options Configuration - */ - -/* - * 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 - * - */ -#ifndef __LWIPOPTS_H__ -#define __LWIPOPTS_H__ - -#define PBUF_RSV_FOR_WLAN -#define EBUF_LWIP - -/* - ----------------------------------------------- - ---------- Platform specific locking ---------- - ----------------------------------------------- -*/ - -/** - * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain - * critical regions during buffer allocation, deallocation and memory - * allocation and deallocation. - */ -#ifndef SYS_LIGHTWEIGHT_PROT -#define SYS_LIGHTWEIGHT_PROT 0 -#endif - -/** - * NO_SYS==1: Provides VERY minimal functionality. Otherwise, - * use lwIP facilities. - */ -#ifndef NO_SYS -#define NO_SYS 1 -#endif - -/** - * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 - * Mainly for compatibility to old versions. - */ -#ifndef NO_SYS_NO_TIMERS -#define NO_SYS_NO_TIMERS 0 -#endif - -/** - * MEMCPY: override this if you have a faster implementation at hand than the - * one included in your C library - */ -#ifndef MEMCPY -#define MEMCPY(dst,src,len) os_memcpy(dst,src,len) -#endif - -/** - * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a - * call to memcpy() if the length is known at compile time and is small. - */ -#ifndef SMEMCPY -#define SMEMCPY(dst,src,len) os_memcpy(dst,src,len) -#endif - -/* - ------------------------------------ - ---------- Memory options ---------- - ------------------------------------ -*/ -/** - * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library - * instead of the lwip internal allocator. Can save code size if you - * already use it. - */ -#ifndef MEM_LIBC_MALLOC -#define MEM_LIBC_MALLOC 1 -#endif - -/** -* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. -* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution -* speed and usage from interrupts! -*/ -#ifndef MEMP_MEM_MALLOC -#define MEMP_MEM_MALLOC 1 -#endif - -/** - * MEM_ALIGNMENT: should be set to the alignment of the CPU - * 4 byte alignment -> #define MEM_ALIGNMENT 4 - * 2 byte alignment -> #define MEM_ALIGNMENT 2 - */ -#ifndef MEM_ALIGNMENT -#define MEM_ALIGNMENT 4 -#endif - -/** - * MEM_SIZE: the size of the heap memory. If the application will send - * a lot of data that needs to be copied, this should be set high. - */ -#ifndef MEM_SIZE -#define MEM_SIZE 16000 -#endif - -/** - * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array. - * This can be used to individually change the location of each pool. - * Default is one big array for all pools - */ -#ifndef MEMP_SEPARATE_POOLS -#define MEMP_SEPARATE_POOLS 1 -#endif - -/** - * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable - * amount of bytes before and after each memp element in every pool and fills - * it with a prominent default value. - * MEMP_OVERFLOW_CHECK == 0 no checking - * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed - * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time - * memp_malloc() or memp_free() is called (useful but slow!) - */ -#ifndef MEMP_OVERFLOW_CHECK -#define MEMP_OVERFLOW_CHECK 0 -#endif - -/** - * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make - * sure that there are no cycles in the linked lists. - */ -#ifndef MEMP_SANITY_CHECK -#define MEMP_SANITY_CHECK 1 -#endif - -/** - * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set - * of memory pools of various sizes. When mem_malloc is called, an element of - * the smallest pool that can provide the length needed is returned. - * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. - */ -#ifndef MEM_USE_POOLS -#define MEM_USE_POOLS 0 -#endif - -/** - * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next - * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more - * reliable. */ -#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL -#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 -#endif - -/** - * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h - * that defines additional pools beyond the "standard" ones required - * by lwIP. If you set this to 1, you must have lwippools.h in your - * inlude path somewhere. - */ -#ifndef MEMP_USE_CUSTOM_POOLS -#define MEMP_USE_CUSTOM_POOLS 0 -#endif - -/** - * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from - * interrupt context (or another context that doesn't allow waiting for a - * semaphore). - * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, - * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs - * with each loop so that mem_free can run. - * - * ATTENTION: As you can see from the above description, this leads to dis-/ - * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc - * can need longer. - * - * If you don't want that, at least for NO_SYS=0, you can still use the following - * functions to enqueue a deallocation call which then runs in the tcpip_thread - * context: - * - pbuf_free_callback(p); - * - mem_free_callback(m); - */ -#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT -#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 -#endif - -/* - ------------------------------------------------ - ---------- Internal Memory Pool Sizes ---------- - ------------------------------------------------ -*/ -/** - * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). - * If the application sends a lot of data out of ROM (or other static memory), - * this should be set high. - */ -#ifndef MEMP_NUM_PBUF -#define MEMP_NUM_PBUF 10 -#endif - -/** - * MEMP_NUM_RAW_PCB: Number of raw connection PCBs - * (requires the LWIP_RAW option) - */ -#ifndef MEMP_NUM_RAW_PCB -#define MEMP_NUM_RAW_PCB 4 -#endif - -/** - * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One - * per active UDP "connection". - * (requires the LWIP_UDP option) - */ -#ifndef MEMP_NUM_UDP_PCB -#define MEMP_NUM_UDP_PCB 4 -#endif - -/** - * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. - * (requires the LWIP_TCP option) - */ -#ifndef MEMP_NUM_TCP_PCB -#define MEMP_NUM_TCP_PCB (*(volatile uint32*)0x600011FC) -#endif - -/** - * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. - * (requires the LWIP_TCP option) - */ -#ifndef MEMP_NUM_TCP_PCB_LISTEN -#define MEMP_NUM_TCP_PCB_LISTEN 2 -#endif - -/** - * MEMP_NUM_TCP_PCB_TIME_WAIT: the number of TCP pcbs in TIME_WAIT state. - * (requires the LWIP_TCP option, 0 = disabled) - */ -#ifndef MEMP_NUM_TCP_PCB_TIME_WAIT -#define MEMP_NUM_TCP_PCB_TIME_WAIT 5 -#endif - -/** - * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. - * (requires the LWIP_TCP option) - */ -#ifndef MEMP_NUM_TCP_SEG -#define MEMP_NUM_TCP_SEG 16 -#endif - -/** - * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for - * reassembly (whole packets, not fragments!) - */ -#ifndef MEMP_NUM_REASSDATA -#define MEMP_NUM_REASSDATA 0 -#endif - -/** - * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent - * (fragments, not whole packets!). - * This is only used with IP_FRAG_USES_STATIC_BUF==0 and - * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs - * where the packet is not yet sent when netif->output returns. - */ -#ifndef MEMP_NUM_FRAG_PBUF -#define MEMP_NUM_FRAG_PBUF 0 -#endif - -/** - * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing - * packets (pbufs) that are waiting for an ARP request (to resolve - * their destination address) to finish. - * (requires the ARP_QUEUEING option) - */ -#ifndef MEMP_NUM_ARP_QUEUE -#define MEMP_NUM_ARP_QUEUE 10 -#endif - -/** - * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces - * can be members et the same time (one per netif - allsystems group -, plus one - * per netif membership). - * (requires the LWIP_IGMP option) - */ -#ifndef MEMP_NUM_IGMP_GROUP -#define MEMP_NUM_IGMP_GROUP 8 -#endif - -/** - * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. - * (requires NO_SYS==0) - */ -#ifndef MEMP_NUM_SYS_TIMEOUT -#define MEMP_NUM_SYS_TIMEOUT 8 -#endif - -/** - * MEMP_NUM_NETBUF: the number of struct netbufs. - * (only needed if you use the sequential API, like api_lib.c) - */ -#ifndef MEMP_NUM_NETBUF -#define MEMP_NUM_NETBUF 0 -#endif - -/** - * MEMP_NUM_NETCONN: the number of struct netconns. - * (only needed if you use the sequential API, like api_lib.c) - */ -#ifndef MEMP_NUM_NETCONN -#define MEMP_NUM_NETCONN 0 -#endif - -/** - * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used - * for callback/timeout API communication. - * (only needed if you use tcpip.c) - */ -#ifndef MEMP_NUM_TCPIP_MSG_API -#define MEMP_NUM_TCPIP_MSG_API 4 -#endif - -/** - * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used - * for incoming packets. - * (only needed if you use tcpip.c) - */ -#ifndef MEMP_NUM_TCPIP_MSG_INPKT -#define MEMP_NUM_TCPIP_MSG_INPKT 4 -#endif - -/** - * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree. - */ -#ifndef MEMP_NUM_SNMP_NODE -#define MEMP_NUM_SNMP_NODE 0 -#endif - -/** - * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree. - * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least! - */ -#ifndef MEMP_NUM_SNMP_ROOTNODE -#define MEMP_NUM_SNMP_ROOTNODE 0 -#endif - -/** - * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to - * be changed normally) - 2 of these are used per request (1 for input, - * 1 for output) - */ -#ifndef MEMP_NUM_SNMP_VARBIND -#define MEMP_NUM_SNMP_VARBIND 0 -#endif - -/** - * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used - * (does not have to be changed normally) - 3 of these are used per request - * (1 for the value read and 2 for OIDs - input and output) - */ -#ifndef MEMP_NUM_SNMP_VALUE -#define MEMP_NUM_SNMP_VALUE 0 -#endif - -/** - * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls - * (before freeing the corresponding memory using lwip_freeaddrinfo()). - */ -#ifndef MEMP_NUM_NETDB -#define MEMP_NUM_NETDB 0 -#endif - -/** - * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list - * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. - */ -#ifndef MEMP_NUM_LOCALHOSTLIST -#define MEMP_NUM_LOCALHOSTLIST 0 -#endif - -/** - * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE - * interfaces (only used with PPPOE_SUPPORT==1) - */ -#ifndef MEMP_NUM_PPPOE_INTERFACES -#define MEMP_NUM_PPPOE_INTERFACES 0 -#endif - -/** - * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. - */ -#ifndef PBUF_POOL_SIZE -#define PBUF_POOL_SIZE 10 -#endif - -/* - --------------------------------- - ---------- ARP options ---------- - --------------------------------- -*/ -/** - * LWIP_ARP==1: Enable ARP functionality. - */ -#ifndef LWIP_ARP -#define LWIP_ARP 1 -#endif - -/** - * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. - */ -#ifndef ARP_TABLE_SIZE -#define ARP_TABLE_SIZE 10 -#endif - -/** - * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address - * resolution. By default, only the most recent packet is queued per IP address. - * This is sufficient for most protocols and mainly reduces TCP connection - * startup time. Set this to 1 if you know your application sends more than one - * packet in a row to an IP address that is not in the ARP cache. - */ -#ifndef ARP_QUEUEING -#define ARP_QUEUEING 1 -#endif - -/** - * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be - * updated with the source MAC and IP addresses supplied in the packet. - * You may want to disable this if you do not trust LAN peers to have the - * correct addresses, or as a limited approach to attempt to handle - * spoofing. If disabled, lwIP will need to make a new ARP request if - * the peer is not already in the ARP table, adding a little latency. - * The peer *is* in the ARP table if it requested our address before. - * Also notice that this slows down input processing of every IP packet! - */ -#ifndef ETHARP_TRUST_IP_MAC -#define ETHARP_TRUST_IP_MAC 1 -#endif - -/** - * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header. - * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. - * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. - * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. - */ -#ifndef ETHARP_SUPPORT_VLAN -#define ETHARP_SUPPORT_VLAN 0 -#endif - -/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP - * might be disabled - */ -#ifndef LWIP_ETHERNET -#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT) -#endif - -/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure - * alignment of payload after that header. Since the header is 14 bytes long, - * without this padding e.g. addresses in the IP header will not be aligned - * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. - */ -#ifndef ETH_PAD_SIZE -#define ETH_PAD_SIZE 0 -#endif - -/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table - * entries (using etharp_add_static_entry/etharp_remove_static_entry). - */ -#ifndef ETHARP_SUPPORT_STATIC_ENTRIES -#define ETHARP_SUPPORT_STATIC_ENTRIES 0 -#endif - - -/* - -------------------------------- - ---------- IP options ---------- - -------------------------------- -*/ -/** - * IP_FORWARD==1: Enables the ability to forward IP packets across network - * interfaces. If you are going to run lwIP on a device with only one network - * interface, define this to 0. - */ -#ifndef IP_FORWARD -#define IP_FORWARD 0 -#endif - -/** - * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. - * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. - * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). - */ -#ifndef IP_OPTIONS_ALLOWED -#define IP_OPTIONS_ALLOWED 1 -#endif - -/** - * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that - * this option does not affect outgoing packet sizes, which can be controlled - * via IP_FRAG. - */ -#ifndef IP_REASSEMBLY -#define IP_REASSEMBLY 0 -#endif - -/** - * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note - * that this option does not affect incoming packet sizes, which can be - * controlled via IP_REASSEMBLY. - */ -#ifndef IP_FRAG -#define IP_FRAG 0 -#endif - -/** - * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) - * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived - * in this time, the whole packet is discarded. - */ -#ifndef IP_REASS_MAXAGE -#define IP_REASS_MAXAGE 3 -#endif - -/** - * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. - * Since the received pbufs are enqueued, be sure to configure - * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive - * packets even if the maximum amount of fragments is enqueued for reassembly! - */ -#ifndef IP_REASS_MAX_PBUFS -#define IP_REASS_MAX_PBUFS 10 -#endif - -/** - * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP - * fragmentation. Otherwise pbufs are allocated and reference the original - * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1, - * new PBUF_RAM pbufs are used for fragments). - * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs! - */ -#ifndef IP_FRAG_USES_STATIC_BUF -#define IP_FRAG_USES_STATIC_BUF 1 -#endif - -/** - * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer - * (requires IP_FRAG_USES_STATIC_BUF==1) - */ -#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) -#define IP_FRAG_MAX_MTU 1500 -#endif - -/** - * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. - */ -#ifndef IP_DEFAULT_TTL -#define IP_DEFAULT_TTL 128 -#endif - -/** - * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast - * filter per pcb on udp and raw send operations. To enable broadcast filter - * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. - */ -#ifndef IP_SOF_BROADCAST -#define IP_SOF_BROADCAST 0 -#endif - -/** - * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast - * filter on recv operations. - */ -#ifndef IP_SOF_BROADCAST_RECV -#define IP_SOF_BROADCAST_RECV 0 -#endif - -/* - ---------------------------------- - ---------- ICMP options ---------- - ---------------------------------- -*/ -/** - * LWIP_ICMP==1: Enable ICMP module inside the IP stack. - * Be careful, disable that make your product non-compliant to RFC1122 - */ -#ifndef LWIP_ICMP -#define LWIP_ICMP 1 -#endif - -/** - * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. - */ -#ifndef ICMP_TTL -#define ICMP_TTL (IP_DEFAULT_TTL) -#endif - -/** - * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) - */ -#ifndef LWIP_BROADCAST_PING -#define LWIP_BROADCAST_PING 0 -#endif - -/** - * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) - */ -#ifndef LWIP_MULTICAST_PING -#define LWIP_MULTICAST_PING 0 -#endif - -/* - --------------------------------- - ---------- RAW options ---------- - --------------------------------- -*/ -/** - * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. - */ -#ifndef LWIP_RAW -#define LWIP_RAW 1 -#endif - -/** - * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. - */ -#ifndef RAW_TTL -#define RAW_TTL (IP_DEFAULT_TTL) -#endif - -/* - ---------------------------------- - ---------- DHCP options ---------- - ---------------------------------- -*/ -/** - * LWIP_DHCP==1: Enable DHCP module. - */ -#ifndef LWIP_DHCP -#define LWIP_DHCP 1 -#endif - -/** - * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. - */ -#ifndef DHCP_DOES_ARP_CHECK -#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) -#endif - -/** - * DHCP_MAXRTX: Maximum number of retries of current request. - */ -#ifndef DHCP_MAXRTX -#define DHCP_MAXRTX (*(volatile uint32*)0x600011E0) -#endif - -/* - ------------------------------------ - ---------- AUTOIP options ---------- - ------------------------------------ -*/ -/** - * LWIP_AUTOIP==1: Enable AUTOIP module. - */ -#ifndef LWIP_AUTOIP -#define LWIP_AUTOIP 0 -#endif - -/** - * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on - * the same interface at the same time. - */ -#ifndef LWIP_DHCP_AUTOIP_COOP -#define LWIP_DHCP_AUTOIP_COOP 0 -#endif - -/** - * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes - * that should be sent before falling back on AUTOIP. This can be set - * as low as 1 to get an AutoIP address very quickly, but you should - * be prepared to handle a changing IP address when DHCP overrides - * AutoIP. - */ -#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES -#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 -#endif - -/* - ---------------------------------- - ---------- SNMP options ---------- - ---------------------------------- -*/ -/** - * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP - * transport. - */ -#ifndef LWIP_SNMP -#define LWIP_SNMP 0 -#endif - -/** - * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will - * allow. At least one request buffer is required. - */ -#ifndef SNMP_CONCURRENT_REQUESTS -#define SNMP_CONCURRENT_REQUESTS 0 -#endif - -/** - * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap - * destination is required - */ -#ifndef SNMP_TRAP_DESTINATIONS -#define SNMP_TRAP_DESTINATIONS 0 -#endif - -/** - * SNMP_PRIVATE_MIB: - */ -#ifndef SNMP_PRIVATE_MIB -#define SNMP_PRIVATE_MIB 0 -#endif - -/** - * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not - * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). - * Unsafe requests are disabled by default! - */ -#ifndef SNMP_SAFE_REQUESTS -#define SNMP_SAFE_REQUESTS 0 -#endif - -/** - * The maximum length of strings used. This affects the size of - * MEMP_SNMP_VALUE elements. - */ -#ifndef SNMP_MAX_OCTET_STRING_LEN -#define SNMP_MAX_OCTET_STRING_LEN 127 -#endif - -/** - * The maximum depth of the SNMP tree. - * With private MIBs enabled, this depends on your MIB! - * This affects the size of MEMP_SNMP_VALUE elements. - */ -#ifndef SNMP_MAX_TREE_DEPTH -#define SNMP_MAX_TREE_DEPTH 15 -#endif - -/** - * The size of the MEMP_SNMP_VALUE elements, normally calculated from - * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH. - */ -#ifndef SNMP_MAX_VALUE_SIZE -#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH)) -#endif - -/* - ---------------------------------- - ---------- IGMP options ---------- - ---------------------------------- -*/ -/** - * LWIP_IGMP==1: Turn on IGMP module. - */ -#ifndef LWIP_IGMP -#define LWIP_IGMP 1 -#endif -/* - ---------------------------------- - ---------- MDNS options ---------- - ---------------------------------- -*/ -/** - * LWIP_MDNS==1: Turn on MDNS module. - */ -#ifndef LWIP_MDNS -#define LWIP_MDNS 1 -#endif - -/* - ---------------------------------- - ---------- DNS options ----------- - ---------------------------------- -*/ -/** - * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS - * transport. - */ -#ifndef LWIP_DNS -#define LWIP_DNS 1 -#endif - -/** DNS maximum number of entries to maintain locally. */ -#ifndef DNS_TABLE_SIZE -#define DNS_TABLE_SIZE 4 -#endif - -/** DNS maximum host name length supported in the name table. */ -#ifndef DNS_MAX_NAME_LENGTH -#define DNS_MAX_NAME_LENGTH 256 -#endif - -/** The maximum of DNS servers */ -#ifndef DNS_MAX_SERVERS -#define DNS_MAX_SERVERS 2 -#endif - -/** DNS do a name checking between the query and the response. */ -#ifndef DNS_DOES_NAME_CHECK -#define DNS_DOES_NAME_CHECK 1 -#endif - -/** DNS message max. size. Default value is RFC compliant. */ -#ifndef DNS_MSG_SIZE -#define DNS_MSG_SIZE 512 -#endif - -/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, - * you have to define - * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} - * (an array of structs name/address, where address is an u32_t in network - * byte order). - * - * Instead, you can also use an external function: - * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) - * that returns the IP address or INADDR_NONE if not found. - */ -#ifndef DNS_LOCAL_HOSTLIST -#define DNS_LOCAL_HOSTLIST 0 -#endif /* DNS_LOCAL_HOSTLIST */ - -/** If this is turned on, the local host-list can be dynamically changed - * at runtime. */ -#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC -#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - -/* - --------------------------------- - ---------- UDP options ---------- - --------------------------------- -*/ -/** - * LWIP_UDP==1: Turn on UDP. - */ -#ifndef LWIP_UDP -#define LWIP_UDP 1 -#endif - -/** - * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) - */ -#ifndef LWIP_UDPLITE -#define LWIP_UDPLITE 0 -#endif - -/** - * UDP_TTL: Default Time-To-Live value. - */ -#ifndef UDP_TTL -#define UDP_TTL (IP_DEFAULT_TTL) -#endif - -/** - * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. - */ -#ifndef LWIP_NETBUF_RECVINFO -#define LWIP_NETBUF_RECVINFO 0 -#endif - -/* - --------------------------------- - ---------- TCP options ---------- - --------------------------------- -*/ -/** - * LWIP_TCP==1: Turn on TCP. - */ -#ifndef LWIP_TCP -#define LWIP_TCP 1 -#endif - -/** - * TCP_TTL: Default Time-To-Live value. - */ -#ifndef TCP_TTL -#define TCP_TTL (IP_DEFAULT_TTL) -#endif - -/** - * TCP_WND: The size of a TCP window. This must be at least - * (2 * TCP_MSS) for things to work well - */ -#ifndef TCP_WND -#define TCP_WND (*(volatile uint32*)0x600011F0) -#endif - -/** - * TCP_MAXRTX: Maximum number of retransmissions of data segments. - */ -#ifndef TCP_MAXRTX -#define TCP_MAXRTX (*(volatile uint32*)0x600011E8) -#endif - -/** - * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. - */ -#ifndef TCP_SYNMAXRTX -#define TCP_SYNMAXRTX (*(volatile uint32*)0x600011E4) -#endif - -/** - * TCP_MAXRTO: Maximum retransmission timeout of data segments. - */ -#ifndef TCP_MAXRTO -#define TCP_MAXRTO 10 -#endif - -/** - * TCP_MINRTO: Minimum retransmission timeout of data segments. - */ -#ifndef TCP_MINRTO -#define TCP_MINRTO 2 -#endif - -/** - * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. - * Define to 0 if your device is low on memory. - */ -#ifndef TCP_QUEUE_OOSEQ -#define TCP_QUEUE_OOSEQ 1 -#endif - -#if 1 -/** - * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, - * you might want to increase this.) - * For the receive side, this MSS is advertised to the remote side - * when opening a connection. For the transmit size, this MSS sets - * an upper limit on the MSS advertised by the remote host. - */ -#ifndef TCP_MSS -#define TCP_MSS 1460 -#endif -#endif - -/** - * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really - * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which - * reflects the available reassembly buffer size at the remote host) and the - * largest size permitted by the IP layer" (RFC 1122) - * Setting this to 1 enables code that checks TCP_MSS against the MTU of the - * netif used for a connection and limits the MSS if it would be too big otherwise. - */ -#ifndef TCP_CALCULATE_EFF_SEND_MSS -#define TCP_CALCULATE_EFF_SEND_MSS 1 -#endif - - -/** - * TCP_SND_BUF: TCP sender buffer space (bytes). - */ -#ifndef TCP_SND_BUF -#define TCP_SND_BUF 2 * TCP_MSS -#endif - -/** - * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least - * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. - */ -#ifndef TCP_SND_QUEUELEN -#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) -#endif - -/** - * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than - * TCP_SND_BUF. It is the amount of space which must be available in the - * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). - */ -#ifndef TCP_SNDLOWAT -#define TCP_SNDLOWAT ((TCP_SND_BUF)/2) -#endif - -/** - * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater - * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below - * this number, select returns writable (combined with TCP_SNDLOWAT). - */ -#ifndef TCP_SNDQUEUELOWAT -#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) -#endif - -/** - * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. - */ -#ifndef TCP_LISTEN_BACKLOG -#define TCP_LISTEN_BACKLOG 0 -#endif - -/** - * The maximum allowed backlog for TCP listen netconns. - * This backlog is used unless another is explicitly specified. - * 0xff is the maximum (u8_t). - */ -#ifndef TCP_DEFAULT_LISTEN_BACKLOG -#define TCP_DEFAULT_LISTEN_BACKLOG 0xff -#endif - -/** - * TCP_OVERSIZE: The maximum number of bytes that tcp_write may - * allocate ahead of time in an attempt to create shorter pbuf chains - * for transmission. The meaningful range is 0 to TCP_MSS. Some - * suggested values are: - * - * 0: Disable oversized allocation. Each tcp_write() allocates a new - pbuf (old behaviour). - * 1: Allocate size-aligned pbufs with minimal excess. Use this if your - * scatter-gather DMA requires aligned fragments. - * 128: Limit the pbuf/memory overhead to 20%. - * TCP_MSS: Try to create unfragmented TCP packets. - * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. - */ -#ifndef TCP_OVERSIZE -#define TCP_OVERSIZE TCP_MSS -#endif - -/** - * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. - */ -#ifndef LWIP_TCP_TIMESTAMPS -#define LWIP_TCP_TIMESTAMPS 0 -#endif - -/** - * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an - * explicit window update - */ -#ifndef TCP_WND_UPDATE_THRESHOLD -#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4) -#endif - -/** - * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. - * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all - * events (accept, sent, etc) that happen in the system. - * LWIP_CALLBACK_API==1: The PCB callback function is called directly - * for the event. - */ -#ifndef LWIP_EVENT_API -#define LWIP_EVENT_API 0 -#define LWIP_CALLBACK_API 1 -#else -#define LWIP_EVENT_API 1 -#define LWIP_CALLBACK_API 0 -#endif - - -/* - ---------------------------------- - ---------- Pbuf options ---------- - ---------------------------------- -*/ -/** - * PBUF_LINK_HLEN: the number of bytes that should be allocated for a - * link level header. The default is 14, the standard value for - * Ethernet. - */ -#ifndef PBUF_LINK_HLEN -#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) -#endif - -/** - * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is - * designed to accomodate single full size TCP frame in one pbuf, including - * TCP_MSS, IP header, and link header. - */ -#ifndef PBUF_POOL_BUFSIZE -#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) -#endif - -/* - ------------------------------------------------ - ---------- Network Interfaces options ---------- - ------------------------------------------------ -*/ -/** - * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname - * field. - */ -#ifndef LWIP_NETIF_HOSTNAME -#define LWIP_NETIF_HOSTNAME 1 -#endif - -/** - * LWIP_NETIF_API==1: Support netif api (in netifapi.c) - */ -#ifndef LWIP_NETIF_API -#define LWIP_NETIF_API 0 -#endif - -/** - * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface - * changes its up/down status (i.e., due to DHCP IP acquistion) - */ -#ifndef LWIP_NETIF_STATUS_CALLBACK -#define LWIP_NETIF_STATUS_CALLBACK 0 -#endif - -/** - * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface - * whenever the link changes (i.e., link down) - */ -#ifndef LWIP_NETIF_LINK_CALLBACK -#define LWIP_NETIF_LINK_CALLBACK 0 -#endif - -/** - * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table - * indices) in struct netif. TCP and UDP can make use of this to prevent - * scanning the ARP table for every sent packet. While this is faster for big - * ARP tables or many concurrent connections, it might be counterproductive - * if you have a tiny ARP table or if there never are concurrent connections. - */ -#ifndef LWIP_NETIF_HWADDRHINT -#define LWIP_NETIF_HWADDRHINT 0 -#endif - -/** - * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP - * address equal to the netif IP address, looping them back up the stack. - */ -#ifndef LWIP_NETIF_LOOPBACK -#define LWIP_NETIF_LOOPBACK 0 -#endif - -/** - * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback - * sending for each netif (0 = disabled) - */ -#ifndef LWIP_LOOPBACK_MAX_PBUFS -#define LWIP_LOOPBACK_MAX_PBUFS 0 -#endif - -/** - * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in - * the system, as netifs must change how they behave depending on this setting - * for the LWIP_NETIF_LOOPBACK option to work. - * Setting this is needed to avoid reentering non-reentrant functions like - * tcp_input(). - * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a - * multithreaded environment like tcpip.c. In this case, netif->input() - * is called directly. - * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. - * The packets are put on a list and netif_poll() must be called in - * the main application loop. - */ -#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING -#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) -#endif - -/** - * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data - * to be sent into one single pbuf. This is for compatibility with DMA-enabled - * MACs that do not support scatter-gather. - * Beware that this might involve CPU-memcpy before transmitting that would not - * be needed without this flag! Use this only if you need to! - * - * @todo: TCP and IP-frag do not work with this, yet: - */ -#ifndef LWIP_NETIF_TX_SINGLE_PBUF -#define LWIP_NETIF_TX_SINGLE_PBUF 1 -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - -/* - ------------------------------------ - ---------- LOOPIF options ---------- - ------------------------------------ -*/ -/** - * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c - */ -#ifndef LWIP_HAVE_LOOPIF -#define LWIP_HAVE_LOOPIF 0 -#endif - -/* - ------------------------------------ - ---------- SLIPIF options ---------- - ------------------------------------ -*/ -/** - * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c - */ -#ifndef LWIP_HAVE_SLIPIF -#define LWIP_HAVE_SLIPIF 0 -#endif - -/* - ------------------------------------ - ---------- Thread options ---------- - ------------------------------------ -*/ -/** - * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. - */ -#ifndef TCPIP_THREAD_NAME -#define TCPIP_THREAD_NAME "tcpip_thread" -#endif - -/** - * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. - * The stack size value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef TCPIP_THREAD_STACKSIZE -#define TCPIP_THREAD_STACKSIZE 0 -#endif - -/** - * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. - * The priority value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef TCPIP_THREAD_PRIO -#define TCPIP_THREAD_PRIO 1 -#endif - -/** - * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages - * The queue size value itself is platform-dependent, but is passed to - * sys_mbox_new() when tcpip_init is called. - */ -#ifndef TCPIP_MBOX_SIZE -#define TCPIP_MBOX_SIZE 0 -#endif - -/** - * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. - */ -#ifndef SLIPIF_THREAD_NAME -#define SLIPIF_THREAD_NAME "slipif_loop" -#endif - -/** - * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. - * The stack size value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef SLIPIF_THREAD_STACKSIZE -#define SLIPIF_THREAD_STACKSIZE 0 -#endif - -/** - * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. - * The priority value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef SLIPIF_THREAD_PRIO -#define SLIPIF_THREAD_PRIO 1 -#endif - -/** - * PPP_THREAD_NAME: The name assigned to the pppInputThread. - */ -#ifndef PPP_THREAD_NAME -#define PPP_THREAD_NAME "pppInputThread" -#endif - -/** - * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread. - * The stack size value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef PPP_THREAD_STACKSIZE -#define PPP_THREAD_STACKSIZE 0 -#endif - -/** - * PPP_THREAD_PRIO: The priority assigned to the pppInputThread. - * The priority value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef PPP_THREAD_PRIO -#define PPP_THREAD_PRIO 1 -#endif - -/** - * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. - */ -#ifndef DEFAULT_THREAD_NAME -#define DEFAULT_THREAD_NAME "lwIP" -#endif - -/** - * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. - * The stack size value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef DEFAULT_THREAD_STACKSIZE -#define DEFAULT_THREAD_STACKSIZE 0 -#endif - -/** - * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. - * The priority value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef DEFAULT_THREAD_PRIO -#define DEFAULT_THREAD_PRIO 1 -#endif - -/** - * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a - * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed - * to sys_mbox_new() when the recvmbox is created. - */ -#ifndef DEFAULT_RAW_RECVMBOX_SIZE -#define DEFAULT_RAW_RECVMBOX_SIZE 0 -#endif - -/** - * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a - * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed - * to sys_mbox_new() when the recvmbox is created. - */ -#ifndef DEFAULT_UDP_RECVMBOX_SIZE -#define DEFAULT_UDP_RECVMBOX_SIZE 0 -#endif - -/** - * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a - * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed - * to sys_mbox_new() when the recvmbox is created. - */ -#ifndef DEFAULT_TCP_RECVMBOX_SIZE -#define DEFAULT_TCP_RECVMBOX_SIZE 0 -#endif - -/** - * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. - * The queue size value itself is platform-dependent, but is passed to - * sys_mbox_new() when the acceptmbox is created. - */ -#ifndef DEFAULT_ACCEPTMBOX_SIZE -#define DEFAULT_ACCEPTMBOX_SIZE 0 -#endif - -/* - ---------------------------------------------- - ---------- Sequential layer options ---------- - ---------------------------------------------- -*/ -/** - * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) - * Don't use it if you're not an active lwIP project member - */ -#ifndef LWIP_TCPIP_CORE_LOCKING -#define LWIP_TCPIP_CORE_LOCKING 0 -#endif - -/** - * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!) - * Don't use it if you're not an active lwIP project member - */ -#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT -#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 -#endif - -/** - * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) - */ -#ifndef LWIP_NETCONN -#define LWIP_NETCONN 0 -#endif - -/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create - * timers running in tcpip_thread from another thread. - */ -#ifndef LWIP_TCPIP_TIMEOUT -#define LWIP_TCPIP_TIMEOUT 1 -#endif - -/* - ------------------------------------ - ---------- Socket options ---------- - ------------------------------------ -*/ -/** - * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) - */ -#ifndef LWIP_SOCKET -#define LWIP_SOCKET 0 -#endif - -/** - * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names. - * (only used if you use sockets.c) - */ -#ifndef LWIP_COMPAT_SOCKETS -#define LWIP_COMPAT_SOCKETS 0 -#endif - -/** - * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. - * Disable this option if you use a POSIX operating system that uses the same - * names (read, write & close). (only used if you use sockets.c) - */ -#ifndef LWIP_POSIX_SOCKETS_IO_NAMES -#define LWIP_POSIX_SOCKETS_IO_NAMES 0 -#endif - -/** - * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT - * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set - * in seconds. (does not require sockets.c, and will affect tcp.c) - */ -#ifndef LWIP_TCP_KEEPALIVE -#define LWIP_TCP_KEEPALIVE 1 -#endif - -/** - * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing. - */ -#ifndef LWIP_SO_RCVTIMEO -#define LWIP_SO_RCVTIMEO 0 -#endif - -/** - * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. - */ -#ifndef LWIP_SO_RCVBUF -#define LWIP_SO_RCVBUF 0 -#endif - -/** - * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. - */ -#ifndef RECV_BUFSIZE_DEFAULT -#define RECV_BUFSIZE_DEFAULT INT_MAX -#endif - -/** - * SO_REUSE==1: Enable SO_REUSEADDR option. - */ -#ifndef SO_REUSE -#define SO_REUSE 1 -#endif - -/** - * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets - * to all local matches if SO_REUSEADDR is turned on. - * WARNING: Adds a memcpy for every packet if passing to more than one pcb! - */ -#ifndef SO_REUSE_RXTOALL -#define SO_REUSE_RXTOALL 0 -#endif - -/* - ---------------------------------------- - ---------- Statistics options ---------- - ---------------------------------------- -*/ -/** - * LWIP_STATS==1: Enable statistics collection in lwip_stats. - */ -#ifndef LWIP_STATS -#define LWIP_STATS 0 -#endif - -#if LWIP_STATS - -/** - * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. - */ -#ifndef LWIP_STATS_DISPLAY -#define LWIP_STATS_DISPLAY 0 -#endif - -/** - * LINK_STATS==1: Enable link stats. - */ -#ifndef LINK_STATS -#define LINK_STATS 1 -#endif - -/** - * ETHARP_STATS==1: Enable etharp stats. - */ -#ifndef ETHARP_STATS -#define ETHARP_STATS (LWIP_ARP) -#endif - -/** - * IP_STATS==1: Enable IP stats. - */ -#ifndef IP_STATS -#define IP_STATS 1 -#endif - -/** - * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is - * on if using either frag or reass. - */ -#ifndef IPFRAG_STATS -#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) -#endif - -/** - * ICMP_STATS==1: Enable ICMP stats. - */ -#ifndef ICMP_STATS -#define ICMP_STATS 1 -#endif - -/** - * IGMP_STATS==1: Enable IGMP stats. - */ -#ifndef IGMP_STATS -#define IGMP_STATS (LWIP_IGMP) -#endif - -/** - * UDP_STATS==1: Enable UDP stats. Default is on if - * UDP enabled, otherwise off. - */ -#ifndef UDP_STATS -#define UDP_STATS (LWIP_UDP) -#endif - -/** - * TCP_STATS==1: Enable TCP stats. Default is on if TCP - * enabled, otherwise off. - */ -#ifndef TCP_STATS -#define TCP_STATS (LWIP_TCP) -#endif - -/** - * MEM_STATS==1: Enable mem.c stats. - */ -#ifndef MEM_STATS -#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) -#endif - -/** - * MEMP_STATS==1: Enable memp.c pool stats. - */ -#ifndef MEMP_STATS -#define MEMP_STATS (MEMP_MEM_MALLOC == 0) -#endif - -/** - * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). - */ -#ifndef SYS_STATS -#define SYS_STATS (NO_SYS == 0) -#endif - -#else -#define ETHARP_STATS 0 -#define LINK_STATS 0 -#define IP_STATS 0 -#define IPFRAG_STATS 0 -#define ICMP_STATS 0 -#define IGMP_STATS 0 -#define UDP_STATS 0 -#define TCP_STATS 0 -#define MEM_STATS 0 -#define MEMP_STATS 0 -#define SYS_STATS 0 -#define LWIP_STATS_DISPLAY 0 - -#endif /* LWIP_STATS */ - -/* - --------------------------------- - ---------- PPP options ---------- - --------------------------------- -*/ -/** - * PPP_SUPPORT==1: Enable PPP. - */ -#ifndef PPP_SUPPORT -#define PPP_SUPPORT 0 -#endif - -/** - * PPPOE_SUPPORT==1: Enable PPP Over Ethernet - */ -#ifndef PPPOE_SUPPORT -#define PPPOE_SUPPORT 0 -#endif - -/** - * PPPOS_SUPPORT==1: Enable PPP Over Serial - */ -#ifndef PPPOS_SUPPORT -#define PPPOS_SUPPORT PPP_SUPPORT -#endif - -#if PPP_SUPPORT - -/** - * NUM_PPP: Max PPP sessions. - */ -#ifndef NUM_PPP -#define NUM_PPP 1 -#endif - -/** - * PAP_SUPPORT==1: Support PAP. - */ -#ifndef PAP_SUPPORT -#define PAP_SUPPORT 0 -#endif - -/** - * CHAP_SUPPORT==1: Support CHAP. - */ -#ifndef CHAP_SUPPORT -#define CHAP_SUPPORT 0 -#endif - -/** - * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET! - */ -#ifndef MSCHAP_SUPPORT -#define MSCHAP_SUPPORT 0 -#endif - -/** - * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! - */ -#ifndef CBCP_SUPPORT -#define CBCP_SUPPORT 0 -#endif - -/** - * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET! - */ -#ifndef CCP_SUPPORT -#define CCP_SUPPORT 0 -#endif - -/** - * VJ_SUPPORT==1: Support VJ header compression. - */ -#ifndef VJ_SUPPORT -#define VJ_SUPPORT 0 -#endif - -/** - * MD5_SUPPORT==1: Support MD5 (see also CHAP). - */ -#ifndef MD5_SUPPORT -#define MD5_SUPPORT 0 -#endif - -/* - * Timeouts - */ -#ifndef FSM_DEFTIMEOUT -#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */ -#endif - -#ifndef FSM_DEFMAXTERMREQS -#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ -#endif - -#ifndef FSM_DEFMAXCONFREQS -#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ -#endif - -#ifndef FSM_DEFMAXNAKLOOPS -#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ -#endif - -#ifndef UPAP_DEFTIMEOUT -#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ -#endif - -#ifndef UPAP_DEFREQTIME -#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ -#endif - -#ifndef CHAP_DEFTIMEOUT -#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */ -#endif - -#ifndef CHAP_DEFTRANSMITS -#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ -#endif - -/* Interval in seconds between keepalive echo requests, 0 to disable. */ -#ifndef LCP_ECHOINTERVAL -#define LCP_ECHOINTERVAL 0 -#endif - -/* Number of unanswered echo requests before failure. */ -#ifndef LCP_MAXECHOFAILS -#define LCP_MAXECHOFAILS 3 -#endif - -/* Max Xmit idle time (in jiffies) before resend flag char. */ -#ifndef PPP_MAXIDLEFLAG -#define PPP_MAXIDLEFLAG 100 -#endif - -/* - * Packet sizes - * - * Note - lcp shouldn't be allowed to negotiate stuff outside these - * limits. See lcp.h in the pppd directory. - * (XXX - these constants should simply be shared by lcp.c instead - * of living in lcp.h) - */ -#define PPP_MTU 1500 /* Default MTU (size of Info field) */ -#ifndef PPP_MAXMTU -/* #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) */ -#define PPP_MAXMTU 1500 /* Largest MTU we allow */ -#endif -#define PPP_MINMTU 64 -#define PPP_MRU 1500 /* default MRU = max length of info field */ -#define PPP_MAXMRU 1500 /* Largest MRU we allow */ -#ifndef PPP_DEFMRU -#define PPP_DEFMRU 296 /* Try for this */ -#endif -#define PPP_MINMRU 128 /* No MRUs below this */ - -#ifndef MAXNAMELEN -#define MAXNAMELEN 256 /* max length of hostname or name for auth */ -#endif -#ifndef MAXSECRETLEN -#define MAXSECRETLEN 256 /* max length of password or secret */ -#endif - -#endif /* PPP_SUPPORT */ - -/* - -------------------------------------- - ---------- Checksum options ---------- - -------------------------------------- -*/ -/** - * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. - */ -#ifndef CHECKSUM_GEN_IP -#define CHECKSUM_GEN_IP 1 -#endif - -/** - * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. - */ -#ifndef CHECKSUM_GEN_UDP -#define CHECKSUM_GEN_UDP 1 -#endif - -/** - * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. - */ -#ifndef CHECKSUM_GEN_TCP -#define CHECKSUM_GEN_TCP 1 -#endif - -/** - * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. - */ -#ifndef CHECKSUM_CHECK_IP -#define CHECKSUM_CHECK_IP 1 -#endif - -/** - * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. - */ -#ifndef CHECKSUM_CHECK_UDP -#define CHECKSUM_CHECK_UDP 1 -#endif - -/** - * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. - */ -#ifndef CHECKSUM_CHECK_TCP -#define CHECKSUM_CHECK_TCP 1 -#endif - -/** - * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from - * application buffers to pbufs. - */ -#ifndef LWIP_CHECKSUM_ON_COPY -#define LWIP_CHECKSUM_ON_COPY 0 -#endif - -/* - --------------------------------------- - ---------- Debugging options ---------- - --------------------------------------- -*/ -/** - * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is - * compared against this value. If it is smaller, then debugging - * messages are written. - */ -#ifndef LWIP_DBG_MIN_LEVEL -#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL -#endif - -/** - * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable - * debug messages of certain types. - */ -#ifndef LWIP_DBG_TYPES_ON -#define LWIP_DBG_TYPES_ON LWIP_DBG_OFF -#endif - -/** - * ETHARP_DEBUG: Enable debugging in etharp.c. - */ -#ifndef ETHARP_DEBUG -#define ETHARP_DEBUG LWIP_DBG_OFF -#endif - -/** - * NETIF_DEBUG: Enable debugging in netif.c. - */ -#ifndef NETIF_DEBUG -#define NETIF_DEBUG LWIP_DBG_OFF -#endif - -/** - * PBUF_DEBUG: Enable debugging in pbuf.c. - */ -#ifndef PBUF_DEBUG -#define PBUF_DEBUG LWIP_DBG_OFF -#endif - -/** - * API_LIB_DEBUG: Enable debugging in api_lib.c. - */ -#ifndef API_LIB_DEBUG -#define API_LIB_DEBUG LWIP_DBG_OFF -#endif - -/** - * API_MSG_DEBUG: Enable debugging in api_msg.c. - */ -#ifndef API_MSG_DEBUG -#define API_MSG_DEBUG LWIP_DBG_OFF -#endif - -/** - * SOCKETS_DEBUG: Enable debugging in sockets.c. - */ -#ifndef SOCKETS_DEBUG -#define SOCKETS_DEBUG LWIP_DBG_OFF -#endif - -/** - * ICMP_DEBUG: Enable debugging in icmp.c. - */ -#ifndef ICMP_DEBUG -#define ICMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * IGMP_DEBUG: Enable debugging in igmp.c. - */ -#ifndef IGMP_DEBUG -#define IGMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * INET_DEBUG: Enable debugging in inet.c. - */ -#ifndef INET_DEBUG -#define INET_DEBUG LWIP_DBG_OFF -#endif - -/** - * IP_DEBUG: Enable debugging for IP. - */ -#ifndef IP_DEBUG -#define IP_DEBUG LWIP_DBG_OFF -#endif - -/** - * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. - */ -#ifndef IP_REASS_DEBUG -#define IP_REASS_DEBUG LWIP_DBG_OFF -#endif - -/** - * RAW_DEBUG: Enable debugging in raw.c. - */ -#ifndef RAW_DEBUG -#define RAW_DEBUG LWIP_DBG_OFF -#endif - -/** - * MEM_DEBUG: Enable debugging in mem.c. - */ -#ifndef MEM_DEBUG -#define MEM_DEBUG LWIP_DBG_OFF -#endif - -/** - * MEMP_DEBUG: Enable debugging in memp.c. - */ -#ifndef MEMP_DEBUG -#define MEMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * SYS_DEBUG: Enable debugging in sys.c. - */ -#ifndef SYS_DEBUG -#define SYS_DEBUG LWIP_DBG_OFF -#endif - -/** - * TIMERS_DEBUG: Enable debugging in timers.c. - */ -#ifndef TIMERS_DEBUG -#define TIMERS_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_DEBUG: Enable debugging for TCP. - */ -#ifndef TCP_DEBUG -#define TCP_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. - */ -#ifndef TCP_INPUT_DEBUG -#define TCP_INPUT_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. - */ -#ifndef TCP_FR_DEBUG -#define TCP_FR_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit - * timeout. - */ -#ifndef TCP_RTO_DEBUG -#define TCP_RTO_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. - */ -#ifndef TCP_CWND_DEBUG -#define TCP_CWND_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. - */ -#ifndef TCP_WND_DEBUG -#define TCP_WND_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. - */ -#ifndef TCP_OUTPUT_DEBUG -#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. - */ -#ifndef TCP_RST_DEBUG -#define TCP_RST_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. - */ -#ifndef TCP_QLEN_DEBUG -#define TCP_QLEN_DEBUG LWIP_DBG_OFF -#endif - -/** - * UDP_DEBUG: Enable debugging in UDP. - */ -#ifndef UDP_DEBUG -#define UDP_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCPIP_DEBUG: Enable debugging in tcpip.c. - */ -#ifndef TCPIP_DEBUG -#define TCPIP_DEBUG LWIP_DBG_OFF -#endif - -/** - * PPP_DEBUG: Enable debugging for PPP. - */ -#ifndef PPP_DEBUG -#define PPP_DEBUG LWIP_DBG_OFF -#endif - -/** - * SLIP_DEBUG: Enable debugging in slipif.c. - */ -#ifndef SLIP_DEBUG -#define SLIP_DEBUG LWIP_DBG_OFF -#endif - -/** - * DHCP_DEBUG: Enable debugging in dhcp.c. - */ -#ifndef DHCP_DEBUG -#define DHCP_DEBUG LWIP_DBG_OFF -#endif - -/** - * AUTOIP_DEBUG: Enable debugging in autoip.c. - */ -#ifndef AUTOIP_DEBUG -#define AUTOIP_DEBUG LWIP_DBG_OFF -#endif - -/** - * SNMP_MSG_DEBUG: Enable debugging for SNMP messages. - */ -#ifndef SNMP_MSG_DEBUG -#define SNMP_MSG_DEBUG LWIP_DBG_OFF -#endif - -/** - * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. - */ -#ifndef SNMP_MIB_DEBUG -#define SNMP_MIB_DEBUG LWIP_DBG_OFF -#endif - -/** - * DNS_DEBUG: Enable debugging for DNS. - */ -#ifndef DNS_DEBUG -#define DNS_DEBUG LWIP_DBG_OFF -#endif - -#endif /* __LWIP_OPT_H__ */ diff --git a/tools/sdk/lwip/include/netif/etharp.h b/tools/sdk/lwip/include/netif/etharp.h deleted file mode 100644 index 2092ab7a1..000000000 --- a/tools/sdk/lwip/include/netif/etharp.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * Copyright (c) 2003-2004 Leon Woestenberg - * Copyright (c) 2003-2004 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. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#ifndef __NETIF_ETHARP_H__ -#define __NETIF_ETHARP_H__ - -#include "lwip/opt.h" - -#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/ip.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef ETHARP_HWADDR_LEN -#define ETHARP_HWADDR_LEN 6 -#endif - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct eth_addr { - PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** Ethernet header */ -struct eth_hdr { -#if ETH_PAD_SIZE - PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); -#endif - PACK_STRUCT_FIELD(struct eth_addr dest); - PACK_STRUCT_FIELD(struct eth_addr src); - PACK_STRUCT_FIELD(u16_t type); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) - -#if ETHARP_SUPPORT_VLAN - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** VLAN header inserted between ethernet header and payload - * if 'type' in ethernet header is ETHTYPE_VLAN. - * See IEEE802.Q */ -struct eth_vlan_hdr { - PACK_STRUCT_FIELD(u16_t tpid); - PACK_STRUCT_FIELD(u16_t prio_vid); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define SIZEOF_VLAN_HDR 4 -#define VLAN_ID(vlan_hdr) (htons((vlan_hdr)->prio_vid) & 0xFFF) - -#endif /* ETHARP_SUPPORT_VLAN */ - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** the ARP message, see RFC 826 ("Packet format") */ -struct etharp_hdr { - PACK_STRUCT_FIELD(u16_t hwtype); - PACK_STRUCT_FIELD(u16_t proto); - PACK_STRUCT_FIELD(u8_t hwlen); - PACK_STRUCT_FIELD(u8_t protolen); - PACK_STRUCT_FIELD(u16_t opcode); - PACK_STRUCT_FIELD(struct eth_addr shwaddr); - PACK_STRUCT_FIELD(struct ip_addr2 sipaddr); - PACK_STRUCT_FIELD(struct eth_addr dhwaddr); - PACK_STRUCT_FIELD(struct ip_addr2 dipaddr); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define SIZEOF_ETHARP_HDR 28 -#define SIZEOF_ETHARP_MINSIZE 46 -#define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR) -#define SIZEOF_ETHARP_WITHPAD (SIZEOF_ETH_HDR + SIZEOF_ETHARP_MINSIZE) - -/** 5 seconds period */ -#define ARP_TMR_INTERVAL 5000 - -#define ETHTYPE_ARP 0x0806 -#define ETHTYPE_IP 0x0800 -#define ETHTYPE_VLAN 0x8100 -#define ETHTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */ -#define ETHTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */ -#define ETHTYPE_PAE 0x888e - -/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables - * or known to be 32-bit aligned within the protocol header. */ -#ifndef ETHADDR32_COPY -#define ETHADDR32_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN) -#endif - -/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local - * variables and known to be 16-bit aligned within the protocol header. */ -#ifndef ETHADDR16_COPY -#define ETHADDR16_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN) -#endif - -#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ - -/** ARP message types (opcodes) */ -#define ARP_REQUEST 1 -#define ARP_REPLY 2 - -/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type) - * to a filter function that returns the correct netif when using multiple - * netifs on one hardware interface where the netif's low-level receive - * routine cannot decide for the correct netif (e.g. when mapping multiple - * IP addresses to one hardware interface). - */ -#ifndef LWIP_ARP_FILTER_NETIF -#define LWIP_ARP_FILTER_NETIF 0 -#endif - -#if ARP_QUEUEING -/** struct for queueing outgoing packets for unknown address - * defined here to be accessed by memp.h - */ -struct etharp_q_entry { - struct etharp_q_entry *next; - struct pbuf *p; -}; -#endif /* ARP_QUEUEING */ - -#define etharp_init() /* Compatibility define, not init needed. */ -void etharp_tmr(void)ICACHE_FLASH_ATTR; -s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, - struct eth_addr **eth_ret, ip_addr_t **ip_ret)ICACHE_FLASH_ATTR; -err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; -err_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)ICACHE_FLASH_ATTR; -err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; -/** For Ethernet network interfaces, we might want to send "gratuitous ARP"; - * this is an ARP packet sent by a node in order to spontaneously cause other - * nodes to update an entry in their ARP cache. - * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ -#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr) -void etharp_cleanup_netif(struct netif *netif); - -#if ETHARP_SUPPORT_STATIC_ENTRIES -err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)ICACHE_FLASH_ATTR; -err_t etharp_remove_static_entry(ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - -#if LWIP_AUTOIP -err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, - const struct eth_addr *ethdst_addr, - const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr, - const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr, - const u16_t opcode)ICACHE_FLASH_ATTR; -#endif /* LWIP_AUTOIP */ - -#endif /* LWIP_ARP */ - -err_t ethernet_input(struct pbuf *p, struct netif *netif)ICACHE_FLASH_ATTR; - -#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0) - -extern const struct eth_addr ethbroadcast, ethzero; - -#endif /* LWIP_ARP || LWIP_ETHERNET */ - -#if 0 -/** Ethernet header */ -#ifndef ETHARP_HWADDR_LEN -#define ETHARP_HWADDR_LEN 6 -#endif - - -struct eth_addr { - PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]); -} PACK_STRUCT_STRUCT; - - -struct eth_hdr { -#if ETH_PAD_SIZE - PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); -#endif - PACK_STRUCT_FIELD(struct eth_addr dest); - PACK_STRUCT_FIELD(struct eth_addr src); - PACK_STRUCT_FIELD(u16_t type); -} PACK_STRUCT_STRUCT; - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __NETIF_ARP_H__ */ diff --git a/tools/sdk/lwip/include/netif/if_llc.h b/tools/sdk/lwip/include/netif/if_llc.h deleted file mode 100644 index ca09b3868..000000000 --- a/tools/sdk/lwip/include/netif/if_llc.h +++ /dev/null @@ -1,173 +0,0 @@ -/* $NetBSD: if_llc.h,v 1.12 1999/11/19 20:41:19 thorpej Exp $ */ - -/*- - * Copyright (c) 1988, 1993 - * The Regents of the University of California. 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. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. - * - * @(#)if_llc.h 8.1 (Berkeley) 6/10/93 - * $FreeBSD$ - */ - -#ifndef _NET_IF_LLC_H_ -#define _NET_IF_LLC_H_ - -/* - * IEEE 802.2 Link Level Control headers, for use in conjunction with - * 802.{3,4,5} media access control methods. - * - * Headers here do not use bit fields due to shortcommings in many - * compilers. - */ - -struct llc { - uint8_t llc_dsap; - uint8_t llc_ssap; - union { - struct { - uint8_t control; - uint8_t format_id; - uint8_t class; - uint8_t window_x2; - } __packed type_u; - struct { - uint8_t num_snd_x2; - uint8_t num_rcv_x2; - } __packed type_i; - struct { - uint8_t control; - uint8_t num_rcv_x2; - } __packed type_s; - struct { - uint8_t control; - /* - * We cannot put the following fields in a structure because - * the structure rounding might cause padding. - */ - uint8_t frmr_rej_pdu0; - uint8_t frmr_rej_pdu1; - uint8_t frmr_control; - uint8_t frmr_control_ext; - uint8_t frmr_cause; - } __packed type_frmr; - struct { - uint8_t control; - uint8_t org_code[3]; - uint16_t ether_type; - } __packed type_snap; - struct { - uint8_t control; - uint8_t control_ext; - } __packed type_raw; - } __packed llc_un; -} __packed; - -struct frmrinfo { - uint8_t frmr_rej_pdu0; - uint8_t frmr_rej_pdu1; - uint8_t frmr_control; - uint8_t frmr_control_ext; - uint8_t frmr_cause; -} __packed; - -#define llc_control llc_un.type_u.control -#define llc_control_ext llc_un.type_raw.control_ext -#define llc_fid llc_un.type_u.format_id -#define llc_class llc_un.type_u.class -#define llc_window llc_un.type_u.window_x2 -#define llc_frmrinfo llc_un.type_frmr.frmr_rej_pdu0 -#define llc_frmr_pdu0 llc_un.type_frmr.frmr_rej_pdu0 -#define llc_frmr_pdu1 llc_un.type_frmr.frmr_rej_pdu1 -#define llc_frmr_control llc_un.type_frmr.frmr_control -#define llc_frmr_control_ext llc_un.type_frmr.frmr_control_ext -#define llc_frmr_cause llc_un.type_frmr.frmr_cause -#define llc_snap llc_un.type_snap - -/* - * Don't use sizeof(struct llc_un) for LLC header sizes - */ -#define LLC_ISFRAMELEN 4 -#define LLC_UFRAMELEN 3 -#define LLC_FRMRLEN 7 -#define LLC_SNAPFRAMELEN 8 - -#ifdef CTASSERT -CTASSERT(sizeof (struct llc) == LLC_SNAPFRAMELEN); -#endif - -/* - * Unnumbered LLC format commands - */ -#define LLC_UI 0x3 -#define LLC_UI_P 0x13 -#define LLC_DISC 0x43 -#define LLC_DISC_P 0x53 -#define LLC_UA 0x63 -#define LLC_UA_P 0x73 -#define LLC_TEST 0xe3 -#define LLC_TEST_P 0xf3 -#define LLC_FRMR 0x87 -#define LLC_FRMR_P 0x97 -#define LLC_DM 0x0f -#define LLC_DM_P 0x1f -#define LLC_XID 0xaf -#define LLC_XID_P 0xbf -#define LLC_SABME 0x6f -#define LLC_SABME_P 0x7f - -/* - * Supervisory LLC commands - */ -#define LLC_RR 0x01 -#define LLC_RNR 0x05 -#define LLC_REJ 0x09 - -/* - * Info format - dummy only - */ -#define LLC_INFO 0x00 - -/* - * ISO PDTR 10178 contains among others - */ -#define LLC_8021D_LSAP 0x42 -#define LLC_X25_LSAP 0x7e -#define LLC_SNAP_LSAP 0xaa -#define LLC_ISO_LSAP 0xfe - -#define RFC1042_LEN 6 -#define RFC1042 {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00} -#define ETHERNET_TUNNEL {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8} - -/* - * copied from sys/net/ethernet.h - */ -#define ETHERTYPE_AARP 0x80F3 /* AppleTalk AARP */ -#define ETHERTYPE_IPX 0x8137 /* Novell (old) NetWare IPX (ECONFIG E option) */ - - - -#endif /* _NET_IF_LLC_H_ */ diff --git a/tools/sdk/lwip/include/netif/ppp_oe.h b/tools/sdk/lwip/include/netif/ppp_oe.h deleted file mode 100644 index e1cdfa519..000000000 --- a/tools/sdk/lwip/include/netif/ppp_oe.h +++ /dev/null @@ -1,190 +0,0 @@ -/***************************************************************************** -* ppp_oe.h - PPP Over Ethernet implementation for lwIP. -* -* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. -* -* The authors hereby grant permission to use, copy, modify, distribute, -* and license this software and its documentation for any purpose, provided -* that existing copyright notices are retained in all copies and that this -* notice and the following disclaimer are included verbatim in any -* distributions. No written agreement, license, or royalty fee is required -* for any of the authorized uses. -* -* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *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 CONTRIBUTORS 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. -* -****************************************************************************** -* REVISION HISTORY -* -* 06-01-01 Marc Boucher -* Ported to lwIP. -*****************************************************************************/ - - - -/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ - -/*- - * Copyright (c) 2002 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Martin Husemann . - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``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 FOUNDATION OR CONTRIBUTORS - * 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. - */ -#ifndef PPP_OE_H -#define PPP_OE_H - -#include "lwip/opt.h" - -#if PPPOE_SUPPORT > 0 - -#include "netif/etharp.h" - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct pppoehdr { - PACK_STRUCT_FIELD(u8_t vertype); - PACK_STRUCT_FIELD(u8_t code); - PACK_STRUCT_FIELD(u16_t session); - PACK_STRUCT_FIELD(u16_t plen); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct pppoetag { - PACK_STRUCT_FIELD(u16_t tag); - PACK_STRUCT_FIELD(u16_t len); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - - -#define PPPOE_STATE_INITIAL 0 -#define PPPOE_STATE_PADI_SENT 1 -#define PPPOE_STATE_PADR_SENT 2 -#define PPPOE_STATE_SESSION 3 -#define PPPOE_STATE_CLOSING 4 -/* passive */ -#define PPPOE_STATE_PADO_SENT 1 - -#define PPPOE_HEADERLEN sizeof(struct pppoehdr) -#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */ - -#define PPPOE_TAG_EOL 0x0000 /* end of list */ -#define PPPOE_TAG_SNAME 0x0101 /* service name */ -#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */ -#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */ -#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */ -#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */ -#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */ -#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */ -#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */ -#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */ - -#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ -#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ -#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ -#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */ -#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */ - -#ifndef ETHERMTU -#define ETHERMTU 1500 -#endif - -/* two byte PPP protocol discriminator, then IP data */ -#define PPPOE_MAXMTU (ETHERMTU-PPPOE_HEADERLEN-2) - -#ifndef PPPOE_MAX_AC_COOKIE_LEN -#define PPPOE_MAX_AC_COOKIE_LEN 64 -#endif - -struct pppoe_softc { - struct pppoe_softc *next; - struct netif *sc_ethif; /* ethernet interface we are using */ - int sc_pd; /* ppp unit number */ - void (*sc_linkStatusCB)(int pd, int up); - - int sc_state; /* discovery phase or session connected */ - struct eth_addr sc_dest; /* hardware address of concentrator */ - u16_t sc_session; /* PPPoE session id */ - -#ifdef PPPOE_TODO - char *sc_service_name; /* if != NULL: requested name of service */ - char *sc_concentrator_name; /* if != NULL: requested concentrator id */ -#endif /* PPPOE_TODO */ - u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */ - size_t sc_ac_cookie_len; /* length of cookie data */ -#ifdef PPPOE_SERVER - u8_t *sc_hunique; /* content of host unique we must echo back */ - size_t sc_hunique_len; /* length of host unique */ -#endif - int sc_padi_retried; /* number of PADI retries already done */ - int sc_padr_retried; /* number of PADR retries already done */ -}; - - -#define pppoe_init() /* compatibility define, no initialization needed */ - -err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr); -err_t pppoe_destroy(struct netif *ifp); - -int pppoe_connect(struct pppoe_softc *sc); -void pppoe_disconnect(struct pppoe_softc *sc); - -void pppoe_disc_input(struct netif *netif, struct pbuf *p); -void pppoe_data_input(struct netif *netif, struct pbuf *p); - -err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb); - -/** used in ppp.c */ -#define PPPOE_HDRLEN (sizeof(struct eth_hdr) + PPPOE_HEADERLEN) - -#endif /* PPPOE_SUPPORT */ - -#endif /* PPP_OE_H */ diff --git a/tools/sdk/lwip/include/netif/wlan_lwip_if.h b/tools/sdk/lwip/include/netif/wlan_lwip_if.h deleted file mode 100644 index ed9c47756..000000000 --- a/tools/sdk/lwip/include/netif/wlan_lwip_if.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2010-2011 Espressif System - * -*/ - -#ifndef _WLAN_LWIP_IF_H_ -#define _WLAN_LWIP_IF_H_ - -#define LWIP_IF0_PRIO 28 -#define LWIP_IF1_PRIO 29 - -enum { - SIG_LWIP_RX = 0, -}; - -struct netif * eagle_lwip_if_alloc(struct ieee80211_conn *conn, const uint8 *macaddr, struct ip_info *info); -struct netif * eagle_lwip_getif(uint8 index); - -#ifndef IOT_SIP_MODE -sint8 ieee80211_output_pbuf(struct netif *ifp, struct pbuf* pb); -#else -sint8 ieee80211_output_pbuf(struct ieee80211_conn *conn, esf_buf *eb); -#endif - -#endif /* _WLAN_LWIP_IF_H_ */ diff --git a/tools/sdk/lwip/src/Makefile b/tools/sdk/lwip/src/Makefile deleted file mode 100644 index 26290cfdb..000000000 --- a/tools/sdk/lwip/src/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -TOOLCHAIN_DIR ?= ../../../xtensa-lx106-elf -TOOLS_PATH ?= $(TOOLCHAIN_DIR)/bin/xtensa-lx106-elf- -LWIP_LIB ?= liblwip_src.a -SDK_PATH ?= $(abspath ../../) - -BUILD_PATH = build -LWIP_SRCS = $(patsubst %.c,$(BUILD_PATH)/%.o,$(wildcard */*.c)) $(patsubst %.c,$(BUILD_PATH)/%.o,$(wildcard */*/*.c)) - -LWIP_INCLUDE = -Ibuild -I$(SDK_PATH)/include -I$(SDK_PATH)/lwip/include -BUILD_FLAGS = -c -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections -BUILD_DEFINES = -D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ -DLWIP_OPEN_SRC - -ifdef WITH_DEBUG_PREFIX_MAP -EXTRA_FLAGS = -fdebug-prefix-map=$(PWD)= -fdebug-prefix-map=$(TOOLCHAIN_DIR)=xtensa-lx106-elf -gno-record-gcc-switches -endif - -CC=$(TOOLS_PATH)gcc -AR=$(TOOLS_PATH)ar - -$(BUILD_PATH)/%.h: - @mkdir -p $(dir $@) - @touch $@ - -$(BUILD_PATH)/%.o: %.c - @mkdir -p $(dir $@) - $(CC) $(BUILD_FLAGS) $(BUILD_DEFINES) $(LWIP_INCLUDE) $(EXTRA_FLAGS) $< -o $@ - -$(LWIP_LIB): $(BUILD_PATH)/user_config.h $(LWIP_SRCS) - $(AR) cru $(LWIP_LIB) $(LWIP_SRCS) - -all: $(LWIP_LIB) - -install: all - cp -f $(LWIP_LIB) $(SDK_PATH)/lib/$(LWIP_LIB) - -release: all - cp -f $(LWIP_LIB) $(SDK_PATH)/lib/liblwip_gcc.a - -clean: - @rm -rf $(BUILD_PATH) $(LWIP_LIB) diff --git a/tools/sdk/lwip/src/api/api_lib.c b/tools/sdk/lwip/src/api/api_lib.c deleted file mode 100644 index 158325b09..000000000 --- a/tools/sdk/lwip/src/api/api_lib.c +++ /dev/null @@ -1,740 +0,0 @@ -/** - * @file - * Sequential API External module - * - */ - -/* - * 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 - * - */ - -/* This is the part of the API that is linked with - the application */ - -#include "lwip/opt.h" - -#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/api.h" -#include "lwip/tcpip.h" -#include "lwip/memp.h" - -#include "lwip/ip.h" -#include "lwip/raw.h" -#include "lwip/udp.h" -#include "lwip/tcp.h" - -#include - -/** - * Create a new netconn (of a specific type) that has a callback function. - * The corresponding pcb is also created. - * - * @param t the type of 'connection' to create (@see enum netconn_type) - * @param proto the IP protocol for RAW IP pcbs - * @param callback a function to call on status changes (RX available, TX'ed) - * @return a newly allocated struct netconn or - * NULL on memory error - */ -struct netconn* -netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) -{ - struct netconn *conn; - struct api_msg msg; - - conn = netconn_alloc(t, callback); - if (conn != NULL) { - msg.function = do_newconn; - msg.msg.msg.n.proto = proto; - msg.msg.conn = conn; - if (TCPIP_APIMSG(&msg) != ERR_OK) { - LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); - LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); - LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); -#if LWIP_TCP - LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); -#endif /* LWIP_TCP */ - sys_sem_free(&conn->op_completed); - sys_mbox_free(&conn->recvmbox); - memp_free(MEMP_NETCONN, conn); - return NULL; - } - } - return conn; -} - -/** - * Close a netconn 'connection' and free its resources. - * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate - * after this returns. - * - * @param conn the netconn to delete - * @return ERR_OK if the connection was deleted - */ -err_t -netconn_delete(struct netconn *conn) -{ - struct api_msg msg; - - /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ - if (conn == NULL) { - return ERR_OK; - } - - msg.function = do_delconn; - msg.msg.conn = conn; - tcpip_apimsg(&msg); - - netconn_free(conn); - - /* don't care for return value of do_delconn since it only calls void functions */ - - return ERR_OK; -} - -/** - * Get the local or remote IP address and port of a netconn. - * For RAW netconns, this returns the protocol instead of a port! - * - * @param conn the netconn to query - * @param addr a pointer to which to save the IP address - * @param port a pointer to which to save the port (or protocol for RAW) - * @param local 1 to get the local IP address, 0 to get the remote one - * @return ERR_CONN for invalid connections - * ERR_OK if the information was retrieved - */ -err_t -netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) -{ - struct api_msg msg; - err_t err; - - LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); - LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); - LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); - - msg.function = do_getaddr; - msg.msg.conn = conn; - msg.msg.msg.ad.ipaddr = addr; - msg.msg.msg.ad.port = port; - msg.msg.msg.ad.local = local; - err = TCPIP_APIMSG(&msg); - - NETCONN_SET_SAFE_ERR(conn, err); - return err; -} - -/** - * Bind a netconn to a specific local IP address and port. - * Binding one netconn twice might not always be checked correctly! - * - * @param conn the netconn to bind - * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY - * to bind to all addresses) - * @param port the local port to bind the netconn to (not used for RAW) - * @return ERR_OK if bound, any other err_t on failure - */ -err_t -netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port) -{ - struct api_msg msg; - err_t err; - - LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); - - msg.function = do_bind; - msg.msg.conn = conn; - msg.msg.msg.bc.ipaddr = addr; - msg.msg.msg.bc.port = port; - err = TCPIP_APIMSG(&msg); - - NETCONN_SET_SAFE_ERR(conn, err); - return err; -} - -/** - * Connect a netconn to a specific remote IP address and port. - * - * @param conn the netconn to connect - * @param addr the remote IP address to connect to - * @param port the remote port to connect to (no used for RAW) - * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise - */ -err_t -netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port) -{ - struct api_msg msg; - err_t err; - - LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); - - msg.function = do_connect; - msg.msg.conn = conn; - msg.msg.msg.bc.ipaddr = addr; - msg.msg.msg.bc.port = port; - /* This is the only function which need to not block tcpip_thread */ - err = tcpip_apimsg(&msg); - - NETCONN_SET_SAFE_ERR(conn, err); - return err; -} - -/** - * Disconnect a netconn from its current peer (only valid for UDP netconns). - * - * @param conn the netconn to disconnect - * @return TODO: return value is not set here... - */ -err_t -netconn_disconnect(struct netconn *conn) -{ - struct api_msg msg; - err_t err; - - LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); - - msg.function = do_disconnect; - msg.msg.conn = conn; - err = TCPIP_APIMSG(&msg); - - NETCONN_SET_SAFE_ERR(conn, err); - return err; -} - -/** - * Set a TCP netconn into listen mode - * - * @param conn the tcp netconn to set to listen mode - * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 - * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns - * don't return any error (yet?)) - */ -err_t -netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) -{ -#if LWIP_TCP - struct api_msg msg; - err_t err; - - /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ - LWIP_UNUSED_ARG(backlog); - - LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); - - msg.function = do_listen; - msg.msg.conn = conn; -#if TCP_LISTEN_BACKLOG - msg.msg.msg.lb.backlog = backlog; -#endif /* TCP_LISTEN_BACKLOG */ - err = TCPIP_APIMSG(&msg); - - NETCONN_SET_SAFE_ERR(conn, err); - return err; -#else /* LWIP_TCP */ - LWIP_UNUSED_ARG(conn); - LWIP_UNUSED_ARG(backlog); - return ERR_ARG; -#endif /* LWIP_TCP */ -} - -/** - * Accept a new connection on a TCP listening netconn. - * - * @param conn the TCP listen netconn - * @param new_conn pointer where the new connection is stored - * @return ERR_OK if a new connection has been received or an error - * code otherwise - */ -err_t -netconn_accept(struct netconn *conn, struct netconn **new_conn) -{ -#if LWIP_TCP - struct netconn *newconn; - err_t err; -#if TCP_LISTEN_BACKLOG - struct api_msg msg; -#endif /* TCP_LISTEN_BACKLOG */ - - LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); - *new_conn = NULL; - LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); - LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;); - - err = conn->last_err; - if (ERR_IS_FATAL(err)) { - /* don't recv on fatal errors: this might block the application task - waiting on acceptmbox forever! */ - return err; - } - -#if LWIP_SO_RCVTIMEO - if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { - NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT); - return ERR_TIMEOUT; - } -#else - sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0); -#endif /* LWIP_SO_RCVTIMEO*/ - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); - - if (newconn == NULL) { - /* connection has been closed */ - NETCONN_SET_SAFE_ERR(conn, ERR_CLSD); - return ERR_CLSD; - } -#if TCP_LISTEN_BACKLOG - /* Let the stack know that we have accepted the connection. */ - msg.function = do_recv; - msg.msg.conn = conn; - /* don't care for the return value of do_recv */ - TCPIP_APIMSG(&msg); -#endif /* TCP_LISTEN_BACKLOG */ - - *new_conn = newconn; - /* don't set conn->last_err: it's only ERR_OK, anyway */ - return ERR_OK; -#else /* LWIP_TCP */ - LWIP_UNUSED_ARG(conn); - LWIP_UNUSED_ARG(new_conn); - return ERR_ARG; -#endif /* LWIP_TCP */ -} - -/** - * Receive data: actual implementation that doesn't care whether pbuf or netbuf - * is received - * - * @param conn the netconn from which to receive data - * @param new_buf pointer where a new pbuf/netbuf is stored when received data - * @return ERR_OK if data has been received, an error code otherwise (timeout, - * memory error or another error) - */ -static err_t -netconn_recv_data(struct netconn *conn, void **new_buf) -{ - void *buf = NULL; - u16_t len; - err_t err; -#if LWIP_TCP - struct api_msg msg; -#endif /* LWIP_TCP */ - - LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); - *new_buf = NULL; - LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); - LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); - - err = conn->last_err; - if (ERR_IS_FATAL(err)) { - /* don't recv on fatal errors: this might block the application task - waiting on recvmbox forever! */ - /* @todo: this does not allow us to fetch data that has been put into recvmbox - before the fatal error occurred - is that a problem? */ - return err; - } - -#if LWIP_SO_RCVTIMEO - if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { - NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT); - return ERR_TIMEOUT; - } -#else - sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); -#endif /* LWIP_SO_RCVTIMEO*/ - -#if LWIP_TCP - if (conn->type == NETCONN_TCP) { - if (!netconn_get_noautorecved(conn) || (buf == NULL)) { - /* Let the stack know that we have taken the data. */ - /* TODO: Speedup: Don't block and wait for the answer here - (to prevent multiple thread-switches). */ - msg.function = do_recv; - msg.msg.conn = conn; - if (buf != NULL) { - msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len; - } else { - msg.msg.msg.r.len = 1; - } - /* don't care for the return value of do_recv */ - TCPIP_APIMSG(&msg); - } - - /* If we are closed, we indicate that we no longer wish to use the socket */ - if (buf == NULL) { - API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); - /* Avoid to lose any previous error code */ - NETCONN_SET_SAFE_ERR(conn, ERR_CLSD); - return ERR_CLSD; - } - len = ((struct pbuf *)buf)->tot_len; - } -#endif /* LWIP_TCP */ -#if LWIP_TCP && (LWIP_UDP || LWIP_RAW) - else -#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ -#if (LWIP_UDP || LWIP_RAW) - { - LWIP_ASSERT("buf != NULL", buf != NULL); - len = netbuf_len((struct netbuf *)buf); - } -#endif /* (LWIP_UDP || LWIP_RAW) */ - -#if LWIP_SO_RCVBUF - SYS_ARCH_DEC(conn->recv_avail, len); -#endif /* LWIP_SO_RCVBUF */ - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); - - LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len)); - - *new_buf = buf; - /* don't set conn->last_err: it's only ERR_OK, anyway */ - return ERR_OK; -} - -/** - * Receive data (in form of a pbuf) from a TCP netconn - * - * @param conn the netconn from which to receive data - * @param new_buf pointer where a new pbuf is stored when received data - * @return ERR_OK if data has been received, an error code otherwise (timeout, - * memory error or another error) - * ERR_ARG if conn is not a TCP netconn - */ -err_t -netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) -{ - LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) && - netconn_type(conn) == NETCONN_TCP, return ERR_ARG;); - - return netconn_recv_data(conn, (void **)new_buf); -} - -/** - * Receive data (in form of a netbuf containing a packet buffer) from a netconn - * - * @param conn the netconn from which to receive data - * @param new_buf pointer where a new netbuf is stored when received data - * @return ERR_OK if data has been received, an error code otherwise (timeout, - * memory error or another error) - */ -err_t -netconn_recv(struct netconn *conn, struct netbuf **new_buf) -{ -#if LWIP_TCP - struct netbuf *buf = NULL; - err_t err; -#endif /* LWIP_TCP */ - - LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); - *new_buf = NULL; - LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); - LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); - -#if LWIP_TCP - if (conn->type == NETCONN_TCP) { - struct pbuf *p = NULL; - /* This is not a listening netconn, since recvmbox is set */ - - buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); - if (buf == NULL) { - NETCONN_SET_SAFE_ERR(conn, ERR_MEM); - return ERR_MEM; - } - - err = netconn_recv_data(conn, (void **)&p); - if (err != ERR_OK) { - memp_free(MEMP_NETBUF, buf); - return err; - } - LWIP_ASSERT("p != NULL", p != NULL); - - buf->p = p; - buf->ptr = p; - buf->port = 0; - ip_addr_set_any(&buf->addr); - *new_buf = buf; - /* don't set conn->last_err: it's only ERR_OK, anyway */ - return ERR_OK; - } else -#endif /* LWIP_TCP */ - { -#if (LWIP_UDP || LWIP_RAW) - return netconn_recv_data(conn, (void **)new_buf); -#endif /* (LWIP_UDP || LWIP_RAW) */ - } -} - -/** - * TCP: update the receive window: by calling this, the application - * tells the stack that it has processed data and is able to accept - * new data. - * ATTENTION: use with care, this is mainly used for sockets! - * Can only be used when calling netconn_set_noautorecved(conn, 1) before. - * - * @param conn the netconn for which to update the receive window - * @param length amount of data processed (ATTENTION: this must be accurate!) - */ -void -netconn_recved(struct netconn *conn, u32_t length) -{ -#if LWIP_TCP - if ((conn != NULL) && (conn->type == NETCONN_TCP) && - (netconn_get_noautorecved(conn))) { - struct api_msg msg; - /* Let the stack know that we have taken the data. */ - /* TODO: Speedup: Don't block and wait for the answer here - (to prevent multiple thread-switches). */ - msg.function = do_recv; - msg.msg.conn = conn; - msg.msg.msg.r.len = length; - /* don't care for the return value of do_recv */ - TCPIP_APIMSG(&msg); - } -#else /* LWIP_TCP */ - LWIP_UNUSED_ARG(conn); - LWIP_UNUSED_ARG(length); -#endif /* LWIP_TCP */ -} - -/** - * Send data (in form of a netbuf) to a specific remote IP address and port. - * Only to be used for UDP and RAW netconns (not TCP). - * - * @param conn the netconn over which to send data - * @param buf a netbuf containing the data to send - * @param addr the remote IP address to which to send the data - * @param port the remote port to which to send the data - * @return ERR_OK if data was sent, any other err_t on error - */ -err_t -netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port) -{ - if (buf != NULL) { - ip_addr_set(&buf->addr, addr); - buf->port = port; - return netconn_send(conn, buf); - } - return ERR_VAL; -} - -/** - * Send data over a UDP or RAW netconn (that is already connected). - * - * @param conn the UDP or RAW netconn over which to send data - * @param buf a netbuf containing the data to send - * @return ERR_OK if data was sent, any other err_t on error - */ -err_t -netconn_send(struct netconn *conn, struct netbuf *buf) -{ - struct api_msg msg; - err_t err; - - LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); - - LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); - msg.function = do_send; - msg.msg.conn = conn; - msg.msg.msg.b = buf; - err = TCPIP_APIMSG(&msg); - - NETCONN_SET_SAFE_ERR(conn, err); - return err; -} - -/** - * Send data over a TCP netconn. - * - * @param conn the TCP netconn over which to send data - * @param dataptr pointer to the application buffer that contains the data to send - * @param size size of the application data to send - * @param apiflags combination of following flags : - * - NETCONN_COPY: data will be copied into memory belonging to the stack - * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent - * - NETCONN_DONTBLOCK: only write the data if all dat can be written at once - * @return ERR_OK if data was sent, any other err_t on error - */ -err_t -netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags) -{ - struct api_msg msg; - err_t err; - - LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); - LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;); - if (size == 0) { - return ERR_OK; - } - - /* @todo: for non-blocking write, check if 'size' would ever fit into - snd_queue or snd_buf */ - msg.function = do_write; - msg.msg.conn = conn; - msg.msg.msg.w.dataptr = dataptr; - msg.msg.msg.w.apiflags = apiflags; - msg.msg.msg.w.len = size; - /* For locking the core: this _can_ be delayed on low memory/low send buffer, - but if it is, this is done inside api_msg.c:do_write(), so we can use the - non-blocking version here. */ - err = TCPIP_APIMSG(&msg); - - NETCONN_SET_SAFE_ERR(conn, err); - return err; -} - -/** - * Close ot shutdown a TCP netconn (doesn't delete it). - * - * @param conn the TCP netconn to close or shutdown - * @param how fully close or only shutdown one side? - * @return ERR_OK if the netconn was closed, any other err_t on error - */ -static err_t -netconn_close_shutdown(struct netconn *conn, u8_t how) -{ - struct api_msg msg; - err_t err; - - LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); - - msg.function = do_close; - msg.msg.conn = conn; - /* shutting down both ends is the same as closing */ - msg.msg.msg.sd.shut = how; - /* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close, - don't use TCPIP_APIMSG here */ - err = tcpip_apimsg(&msg); - - NETCONN_SET_SAFE_ERR(conn, err); - return err; -} - -/** - * Close a TCP netconn (doesn't delete it). - * - * @param conn the TCP netconn to close - * @return ERR_OK if the netconn was closed, any other err_t on error - */ -err_t -netconn_close(struct netconn *conn) -{ - /* shutting down both ends is the same as closing */ - return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR); -} - -/** - * Shut down one or both sides of a TCP netconn (doesn't delete it). - * - * @param conn the TCP netconn to shut down - * @return ERR_OK if the netconn was closed, any other err_t on error - */ -err_t -netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) -{ - return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)); -} - -#if LWIP_IGMP -/** - * Join multicast groups for UDP netconns. - * - * @param conn the UDP netconn for which to change multicast addresses - * @param multiaddr IP address of the multicast group to join or leave - * @param netif_addr the IP address of the network interface on which to send - * the igmp message - * @param join_or_leave flag whether to send a join- or leave-message - * @return ERR_OK if the action was taken, any err_t on error - */ -err_t -netconn_join_leave_group(struct netconn *conn, - ip_addr_t *multiaddr, - ip_addr_t *netif_addr, - enum netconn_igmp join_or_leave) -{ - struct api_msg msg; - err_t err; - - LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); - - msg.function = do_join_leave_group; - msg.msg.conn = conn; - msg.msg.msg.jl.multiaddr = multiaddr; - msg.msg.msg.jl.netif_addr = netif_addr; - msg.msg.msg.jl.join_or_leave = join_or_leave; - err = TCPIP_APIMSG(&msg); - - NETCONN_SET_SAFE_ERR(conn, err); - return err; -} -#endif /* LWIP_IGMP */ - -#if LWIP_DNS -/** - * Execute a DNS query, only one IP address is returned - * - * @param name a string representation of the DNS host name to query - * @param addr a preallocated ip_addr_t where to store the resolved IP address - * @return ERR_OK: resolving succeeded - * ERR_MEM: memory error, try again later - * ERR_ARG: dns client not initialized or invalid hostname - * ERR_VAL: dns server response was invalid - */ -err_t -netconn_gethostbyname(const char *name, ip_addr_t *addr) -{ - struct dns_api_msg msg; - err_t err; - sys_sem_t sem; - - LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); - LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); - - err = sys_sem_new(&sem, 0); - if (err != ERR_OK) { - return err; - } - - msg.name = name; - msg.addr = addr; - msg.err = &err; - msg.sem = &sem; - - tcpip_callback(do_gethostbyname, &msg); - sys_sem_wait(&sem); - sys_sem_free(&sem); - - return err; -} -#endif /* LWIP_DNS*/ - -#endif /* LWIP_NETCONN */ diff --git a/tools/sdk/lwip/src/api/api_msg.c b/tools/sdk/lwip/src/api/api_msg.c deleted file mode 100644 index dcb07e9c6..000000000 --- a/tools/sdk/lwip/src/api/api_msg.c +++ /dev/null @@ -1,1540 +0,0 @@ -/** - * @file - * Sequential API Internal module - * - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" - -#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/api_msg.h" - -#include "lwip/ip.h" -#include "lwip/udp.h" -#include "lwip/tcp.h" -#include "lwip/raw.h" - -#include "lwip/memp.h" -#include "lwip/tcpip.h" -#include "lwip/igmp.h" -#include "lwip/dns.h" - -#include - -#define SET_NONBLOCKING_CONNECT(conn, val) do { if(val) { \ - (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \ -} else { \ - (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0) -#define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0) - -/* forward declarations */ -#if LWIP_TCP -static err_t do_writemore(struct netconn *conn); -static void do_close_internal(struct netconn *conn); -#endif - -#if LWIP_RAW -/** - * Receive callback function for RAW netconns. - * Doesn't 'eat' the packet, only references it and sends it to - * conn->recvmbox - * - * @see raw.h (struct raw_pcb.recv) for parameters and return value - */ -static u8_t -recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, - ip_addr_t *addr) -{ - struct pbuf *q; - struct netbuf *buf; - struct netconn *conn; - - LWIP_UNUSED_ARG(addr); - conn = (struct netconn *)arg; - - if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) { -#if LWIP_SO_RCVBUF - int recv_avail; - SYS_ARCH_GET(conn->recv_avail, recv_avail); - if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { - return 0; - } -#endif /* LWIP_SO_RCVBUF */ - /* copy the whole packet into new pbufs */ - q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if(q != NULL) { - if (pbuf_copy(q, p) != ERR_OK) { - pbuf_free(q); - q = NULL; - } - } - - if (q != NULL) { - u16_t len; - buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); - if (buf == NULL) { - pbuf_free(q); - return 0; - } - - buf->p = q; - buf->ptr = q; - ip_addr_copy(buf->addr, *ip_current_src_addr()); - buf->port = pcb->protocol; - - len = q->tot_len; - if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { - netbuf_delete(buf); - return 0; - } else { -#if LWIP_SO_RCVBUF - SYS_ARCH_INC(conn->recv_avail, len); -#endif /* LWIP_SO_RCVBUF */ - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); - } - } - } - - return 0; /* do not eat the packet */ -} -#endif /* LWIP_RAW*/ - -#if LWIP_UDP -/** - * Receive callback function for UDP netconns. - * Posts the packet to conn->recvmbox or deletes it on memory error. - * - * @see udp.h (struct udp_pcb.recv) for parameters - */ -static void -recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, - ip_addr_t *addr, u16_t port) -{ - struct netbuf *buf; - struct netconn *conn; - u16_t len; -#if LWIP_SO_RCVBUF - int recv_avail; -#endif /* LWIP_SO_RCVBUF */ - - LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ - LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); - LWIP_ASSERT("recv_udp must have an argument", arg != NULL); - conn = (struct netconn *)arg; - LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); - -#if LWIP_SO_RCVBUF - SYS_ARCH_GET(conn->recv_avail, recv_avail); - if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) || - ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { -#else /* LWIP_SO_RCVBUF */ - if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) { -#endif /* LWIP_SO_RCVBUF */ - pbuf_free(p); - return; - } - - buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); - if (buf == NULL) { - pbuf_free(p); - return; - } else { - buf->p = p; - buf->ptr = p; - ip_addr_set(&buf->addr, addr); - buf->port = port; -#if LWIP_NETBUF_RECVINFO - { - const struct ip_hdr* iphdr = ip_current_header(); - /* get the UDP header - always in the first pbuf, ensured by udp_input */ - const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr)); -#if LWIP_CHECKSUM_ON_COPY - buf->flags = NETBUF_FLAG_DESTADDR; -#endif /* LWIP_CHECKSUM_ON_COPY */ - ip_addr_set(&buf->toaddr, ip_current_dest_addr()); - buf->toport_chksum = udphdr->dest; - } -#endif /* LWIP_NETBUF_RECVINFO */ - } - - len = p->tot_len; - if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { - netbuf_delete(buf); - return; - } else { -#if LWIP_SO_RCVBUF - SYS_ARCH_INC(conn->recv_avail, len); -#endif /* LWIP_SO_RCVBUF */ - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); - } -} -#endif /* LWIP_UDP */ - -#if LWIP_TCP -/** - * Receive callback function for TCP netconns. - * Posts the packet to conn->recvmbox, but doesn't delete it on errors. - * - * @see tcp.h (struct tcp_pcb.recv) for parameters and return value - */ -static err_t -recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) -{ - struct netconn *conn; - u16_t len; - - LWIP_UNUSED_ARG(pcb); - LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); - LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); - conn = (struct netconn *)arg; - LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); - - if (conn == NULL) { - return ERR_VAL; - } - if (!sys_mbox_valid(&conn->recvmbox)) { - /* recvmbox already deleted */ - if (p != NULL) { - tcp_recved(pcb, p->tot_len); - pbuf_free(p); - } - return ERR_OK; - } - /* Unlike for UDP or RAW pcbs, don't check for available space - using recv_avail since that could break the connection - (data is already ACKed) */ - - /* don't overwrite fatal errors! */ - NETCONN_SET_SAFE_ERR(conn, err); - - if (p != NULL) { - len = p->tot_len; - } else { - len = 0; - } - - if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) { - /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ - return ERR_MEM; - } else { -#if LWIP_SO_RCVBUF - SYS_ARCH_INC(conn->recv_avail, len); -#endif /* LWIP_SO_RCVBUF */ - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); - } - - return ERR_OK; -} - -/** - * Poll callback function for TCP netconns. - * Wakes up an application thread that waits for a connection to close - * or data to be sent. The application thread then takes the - * appropriate action to go on. - * - * Signals the conn->sem. - * netconn_close waits for conn->sem if closing failed. - * - * @see tcp.h (struct tcp_pcb.poll) for parameters and return value - */ -static err_t -poll_tcp(void *arg, struct tcp_pcb *pcb) -{ - struct netconn *conn = (struct netconn *)arg; - - LWIP_UNUSED_ARG(pcb); - LWIP_ASSERT("conn != NULL", (conn != NULL)); - - if (conn->state == NETCONN_WRITE) { - do_writemore(conn); - } else if (conn->state == NETCONN_CLOSE) { - do_close_internal(conn); - } - /* @todo: implement connect timeout here? */ - - /* Did a nonblocking write fail before? Then check available write-space. */ - if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { - /* If the queued byte- or pbuf-count drops below the configured low-water limit, - let select mark this pcb as writable again. */ - if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && - (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { - conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; - API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); - } - } - - return ERR_OK; -} - -/** - * Sent callback function for TCP netconns. - * Signals the conn->sem and calls API_EVENT. - * netconn_write waits for conn->sem if send buffer is low. - * - * @see tcp.h (struct tcp_pcb.sent) for parameters and return value - */ -static err_t -sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) -{ - struct netconn *conn = (struct netconn *)arg; - - LWIP_UNUSED_ARG(pcb); - LWIP_ASSERT("conn != NULL", (conn != NULL)); - - if (conn->state == NETCONN_WRITE) { - do_writemore(conn); - } else if (conn->state == NETCONN_CLOSE) { - do_close_internal(conn); - } - - if (conn) { - /* If the queued byte- or pbuf-count drops below the configured low-water limit, - let select mark this pcb as writable again. */ - if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && - (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { - conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; - API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); - } - } - - return ERR_OK; -} - -/** - * Error callback function for TCP netconns. - * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. - * The application thread has then to decide what to do. - * - * @see tcp.h (struct tcp_pcb.err) for parameters - */ -static void -err_tcp(void *arg, err_t err) -{ - struct netconn *conn; - enum netconn_state old_state; - SYS_ARCH_DECL_PROTECT(lev); - - conn = (struct netconn *)arg; - LWIP_ASSERT("conn != NULL", (conn != NULL)); - - conn->pcb.tcp = NULL; - - /* no check since this is always fatal! */ - SYS_ARCH_PROTECT(lev); - conn->last_err = err; - SYS_ARCH_UNPROTECT(lev); - - /* reset conn->state now before waking up other threads */ - old_state = conn->state; - conn->state = NETCONN_NONE; - - /* Notify the user layer about a connection error. Used to signal - select. */ - API_EVENT(conn, NETCONN_EVT_ERROR, 0); - /* Try to release selects pending on 'read' or 'write', too. - They will get an error if they actually try to read or write. */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); - - /* pass NULL-message to recvmbox to wake up pending recv */ - if (sys_mbox_valid(&conn->recvmbox)) { - /* use trypost to prevent deadlock */ - sys_mbox_trypost(&conn->recvmbox, NULL); - } - /* pass NULL-message to acceptmbox to wake up pending accept */ - if (sys_mbox_valid(&conn->acceptmbox)) { - /* use trypost to preven deadlock */ - sys_mbox_trypost(&conn->acceptmbox, NULL); - } - - if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || - (old_state == NETCONN_CONNECT)) { - /* calling do_writemore/do_close_internal is not necessary - since the pcb has already been deleted! */ - int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); - SET_NONBLOCKING_CONNECT(conn, 0); - - if (!was_nonblocking_connect) { - /* set error return code */ - LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); - conn->current_msg->err = err; - conn->current_msg = NULL; - /* wake up the waiting task */ - sys_sem_signal(&conn->op_completed); - } - } else { - LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); - } -} - -/** - * Setup a tcp_pcb with the correct callback function pointers - * and their arguments. - * - * @param conn the TCP netconn to setup - */ -static void -setup_tcp(struct netconn *conn) -{ - struct tcp_pcb *pcb; - - pcb = conn->pcb.tcp; - tcp_arg(pcb, conn); - tcp_recv(pcb, recv_tcp); - tcp_sent(pcb, sent_tcp); - tcp_poll(pcb, poll_tcp, 4); - tcp_err(pcb, err_tcp); -} - -/** - * Accept callback function for TCP netconns. - * Allocates a new netconn and posts that to conn->acceptmbox. - * - * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value - */ -static err_t -accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) -{ - struct netconn *newconn; - struct netconn *conn = (struct netconn *)arg; - - LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state))); - - if (!sys_mbox_valid(&conn->acceptmbox)) { - LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); - return ERR_VAL; - } - - /* We have to set the callback here even though - * the new socket is unknown. conn->socket is marked as -1. */ - newconn = netconn_alloc(conn->type, conn->callback); - if (newconn == NULL) { - return ERR_MEM; - } - newconn->pcb.tcp = newpcb; - setup_tcp(newconn); - /* no protection: when creating the pcb, the netconn is not yet known - to the application thread */ - newconn->last_err = err; - - if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { - /* When returning != ERR_OK, the pcb is aborted in tcp_process(), - so do nothing here! */ - newconn->pcb.tcp = NULL; - /* no need to drain since we know the recvmbox is empty. */ - sys_mbox_free(&newconn->recvmbox); - sys_mbox_set_invalid(&newconn->recvmbox); - netconn_free(newconn); - return ERR_MEM; - } else { - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - } - - return ERR_OK; -} -#endif /* LWIP_TCP */ - -/** - * Create a new pcb of a specific type. - * Called from do_newconn(). - * - * @param msg the api_msg_msg describing the connection type - * @return msg->conn->err, but the return value is currently ignored - */ -static void -pcb_new(struct api_msg_msg *msg) -{ - LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); - - /* Allocate a PCB for this connection */ - switch(NETCONNTYPE_GROUP(msg->conn->type)) { -#if LWIP_RAW - case NETCONN_RAW: - msg->conn->pcb.raw = raw_new(msg->msg.n.proto); - if(msg->conn->pcb.raw == NULL) { - msg->err = ERR_MEM; - break; - } - raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); - break; -#endif /* LWIP_RAW */ -#if LWIP_UDP - case NETCONN_UDP: - msg->conn->pcb.udp = udp_new(); - if(msg->conn->pcb.udp == NULL) { - msg->err = ERR_MEM; - break; - } -#if LWIP_UDPLITE - if (msg->conn->type==NETCONN_UDPLITE) { - udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); - } -#endif /* LWIP_UDPLITE */ - if (msg->conn->type==NETCONN_UDPNOCHKSUM) { - udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); - } - udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case NETCONN_TCP: - msg->conn->pcb.tcp = tcp_new(); - if(msg->conn->pcb.tcp == NULL) { - msg->err = ERR_MEM; - break; - } - setup_tcp(msg->conn); - break; -#endif /* LWIP_TCP */ - default: - /* Unsupported netconn type, e.g. protocol disabled */ - msg->err = ERR_VAL; - break; - } -} - -/** - * Create a new pcb of a specific type inside a netconn. - * Called from netconn_new_with_proto_and_callback. - * - * @param msg the api_msg_msg describing the connection type - */ -void -do_newconn(struct api_msg_msg *msg) -{ - msg->err = ERR_OK; - if(msg->conn->pcb.tcp == NULL) { - pcb_new(msg); - } - /* Else? This "new" connection already has a PCB allocated. */ - /* Is this an error condition? Should it be deleted? */ - /* We currently just are happy and return. */ - - TCPIP_APIMSG_ACK(msg); -} - -/** - * Create a new netconn (of a specific type) that has a callback function. - * The corresponding pcb is NOT created! - * - * @param t the type of 'connection' to create (@see enum netconn_type) - * @param proto the IP protocol for RAW IP pcbs - * @param callback a function to call on status changes (RX available, TX'ed) - * @return a newly allocated struct netconn or - * NULL on memory error - */ -struct netconn* -netconn_alloc(enum netconn_type t, netconn_callback callback) -{ - struct netconn *conn; - int size; - - conn = (struct netconn *)memp_malloc(MEMP_NETCONN); - if (conn == NULL) { - return NULL; - } - - conn->last_err = ERR_OK; - conn->type = t; - conn->pcb.tcp = NULL; - -#if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \ - (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE) - size = DEFAULT_RAW_RECVMBOX_SIZE; -#else - switch(NETCONNTYPE_GROUP(t)) { -#if LWIP_RAW - case NETCONN_RAW: - size = DEFAULT_RAW_RECVMBOX_SIZE; - break; -#endif /* LWIP_RAW */ -#if LWIP_UDP - case NETCONN_UDP: - size = DEFAULT_UDP_RECVMBOX_SIZE; - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case NETCONN_TCP: - size = DEFAULT_TCP_RECVMBOX_SIZE; - break; -#endif /* LWIP_TCP */ - default: - LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); - break; - } -#endif - - if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { - memp_free(MEMP_NETCONN, conn); - return NULL; - } - if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { - sys_sem_free(&conn->op_completed); - memp_free(MEMP_NETCONN, conn); - return NULL; - } - -#if LWIP_TCP - sys_mbox_set_invalid(&conn->acceptmbox); -#endif - conn->state = NETCONN_NONE; -#if LWIP_SOCKET - /* initialize socket to -1 since 0 is a valid socket */ - conn->socket = -1; -#endif /* LWIP_SOCKET */ - conn->callback = callback; -#if LWIP_TCP - conn->current_msg = NULL; - conn->write_offset = 0; -#endif /* LWIP_TCP */ -#if LWIP_SO_RCVTIMEO - conn->recv_timeout = 0; -#endif /* LWIP_SO_RCVTIMEO */ -#if LWIP_SO_RCVBUF - conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; - conn->recv_avail = 0; -#endif /* LWIP_SO_RCVBUF */ - conn->flags = 0; - return conn; -} - -/** - * Delete a netconn and all its resources. - * The pcb is NOT freed (since we might not be in the right thread context do this). - * - * @param conn the netconn to free - */ -void -netconn_free(struct netconn *conn) -{ - LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); - LWIP_ASSERT("recvmbox must be deallocated before calling this function", - !sys_mbox_valid(&conn->recvmbox)); -#if LWIP_TCP - LWIP_ASSERT("acceptmbox must be deallocated before calling this function", - !sys_mbox_valid(&conn->acceptmbox)); -#endif /* LWIP_TCP */ - - sys_sem_free(&conn->op_completed); - sys_sem_set_invalid(&conn->op_completed); - - memp_free(MEMP_NETCONN, conn); -} - -/** - * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in - * these mboxes - * - * @param conn the netconn to free - * @bytes_drained bytes drained from recvmbox - * @accepts_drained pending connections drained from acceptmbox - */ -static void -netconn_drain(struct netconn *conn) -{ - void *mem; -#if LWIP_TCP - struct pbuf *p; -#endif /* LWIP_TCP */ - - /* This runs in tcpip_thread, so we don't need to lock against rx packets */ - - /* Delete and drain the recvmbox. */ - if (sys_mbox_valid(&conn->recvmbox)) { - while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { -#if LWIP_TCP - if (conn->type == NETCONN_TCP) { - if(mem != NULL) { - p = (struct pbuf*)mem; - /* pcb might be set to NULL already by err_tcp() */ - if (conn->pcb.tcp != NULL) { - tcp_recved(conn->pcb.tcp, p->tot_len); - } - pbuf_free(p); - } - } else -#endif /* LWIP_TCP */ - { - netbuf_delete((struct netbuf *)mem); - } - } - sys_mbox_free(&conn->recvmbox); - sys_mbox_set_invalid(&conn->recvmbox); - } - - /* Delete and drain the acceptmbox. */ -#if LWIP_TCP - if (sys_mbox_valid(&conn->acceptmbox)) { - while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { - struct netconn *newconn = (struct netconn *)mem; - /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ - /* pcb might be set to NULL already by err_tcp() */ - if (conn->pcb.tcp != NULL) { - tcp_accepted(conn->pcb.tcp); - } - /* drain recvmbox */ - netconn_drain(newconn); - if (newconn->pcb.tcp != NULL) { - tcp_abort(newconn->pcb.tcp); - newconn->pcb.tcp = NULL; - } - netconn_free(newconn); - } - sys_mbox_free(&conn->acceptmbox); - sys_mbox_set_invalid(&conn->acceptmbox); - } -#endif /* LWIP_TCP */ -} - -#if LWIP_TCP -/** - * Internal helper function to close a TCP netconn: since this sometimes - * doesn't work at the first attempt, this function is called from multiple - * places. - * - * @param conn the TCP netconn to close - */ -static void -do_close_internal(struct netconn *conn) -{ - err_t err; - u8_t shut, shut_rx, shut_tx, close; - - LWIP_ASSERT("invalid conn", (conn != NULL)); - LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); - LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); - LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); - LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); - - shut = conn->current_msg->msg.sd.shut; - shut_rx = shut & NETCONN_SHUT_RD; - shut_tx = shut & NETCONN_SHUT_WR; - /* shutting down both ends is the same as closing */ - close = shut == NETCONN_SHUT_RDWR; - - /* Set back some callback pointers */ - if (close) { - tcp_arg(conn->pcb.tcp, NULL); - } - if (conn->pcb.tcp->state == LISTEN) { - tcp_accept(conn->pcb.tcp, NULL); - } else { - /* some callbacks have to be reset if tcp_close is not successful */ - if (shut_rx) { - tcp_recv(conn->pcb.tcp, NULL); - tcp_accept(conn->pcb.tcp, NULL); - } - if (shut_tx) { - tcp_sent(conn->pcb.tcp, NULL); - } - if (close) { - tcp_poll(conn->pcb.tcp, NULL, 4); - tcp_err(conn->pcb.tcp, NULL); - } - } - /* Try to close the connection */ - if (shut == NETCONN_SHUT_RDWR) { - err = tcp_close(conn->pcb.tcp); - } else { - err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR); - } - if (err == ERR_OK) { - /* Closing succeeded */ - conn->current_msg->err = ERR_OK; - conn->current_msg = NULL; - conn->state = NETCONN_NONE; - /* Set back some callback pointers as conn is going away */ - conn->pcb.tcp = NULL; - /* Trigger select() in socket layer. Make sure everybody notices activity - on the connection, error first! */ - if (close) { - API_EVENT(conn, NETCONN_EVT_ERROR, 0); - } - if (shut_rx) { - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - } - if (shut_tx) { - API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); - } - /* wake up the application task */ - sys_sem_signal(&conn->op_completed); - } else { - /* Closing failed, restore some of the callbacks */ - /* Closing of listen pcb will never fail! */ - LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN)); - tcp_sent(conn->pcb.tcp, sent_tcp); - tcp_poll(conn->pcb.tcp, poll_tcp, 4); - tcp_err(conn->pcb.tcp, err_tcp); - tcp_arg(conn->pcb.tcp, conn); - /* don't restore recv callback: we don't want to receive any more data */ - } - /* If closing didn't succeed, we get called again either - from poll_tcp or from sent_tcp */ -} -#endif /* LWIP_TCP */ - -/** - * Delete the pcb inside a netconn. - * Called from netconn_delete. - * - * @param msg the api_msg_msg pointing to the connection - */ -void -do_delconn(struct api_msg_msg *msg) -{ - /* @todo TCP: abort running write/connect? */ - if ((msg->conn->state != NETCONN_NONE) && - (msg->conn->state != NETCONN_LISTEN) && - (msg->conn->state != NETCONN_CONNECT)) { - /* this only happens for TCP netconns */ - LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); - msg->err = ERR_INPROGRESS; - } else { - LWIP_ASSERT("blocking connect in progress", - (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); - /* Drain and delete mboxes */ - netconn_drain(msg->conn); - - if (msg->conn->pcb.tcp != NULL) { - - switch (NETCONNTYPE_GROUP(msg->conn->type)) { -#if LWIP_RAW - case NETCONN_RAW: - raw_remove(msg->conn->pcb.raw); - break; -#endif /* LWIP_RAW */ -#if LWIP_UDP - case NETCONN_UDP: - msg->conn->pcb.udp->recv_arg = NULL; - udp_remove(msg->conn->pcb.udp); - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case NETCONN_TCP: - LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && - msg->conn->write_offset == 0); - msg->conn->state = NETCONN_CLOSE; - msg->msg.sd.shut = NETCONN_SHUT_RDWR; - msg->conn->current_msg = msg; - do_close_internal(msg->conn); - /* API_EVENT is called inside do_close_internal, before releasing - the application thread, so we can return at this point! */ - return; -#endif /* LWIP_TCP */ - default: - break; - } - msg->conn->pcb.tcp = NULL; - } - /* tcp netconns don't come here! */ - - /* @todo: this lets select make the socket readable and writable, - which is wrong! errfd instead? */ - API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); - API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); - } - if (sys_sem_valid(&msg->conn->op_completed)) { - sys_sem_signal(&msg->conn->op_completed); - } -} - -/** - * Bind a pcb contained in a netconn - * Called from netconn_bind. - * - * @param msg the api_msg_msg pointing to the connection and containing - * the IP address and port to bind to - */ -void -do_bind(struct api_msg_msg *msg) -{ - if (ERR_IS_FATAL(msg->conn->last_err)) { - msg->err = msg->conn->last_err; - } else { - msg->err = ERR_VAL; - if (msg->conn->pcb.tcp != NULL) { - switch (NETCONNTYPE_GROUP(msg->conn->type)) { -#if LWIP_RAW - case NETCONN_RAW: - msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); - break; -#endif /* LWIP_RAW */ -#if LWIP_UDP - case NETCONN_UDP: - msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case NETCONN_TCP: - msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port); - break; -#endif /* LWIP_TCP */ - default: - break; - } - } - } - TCPIP_APIMSG_ACK(msg); -} - -#if LWIP_TCP -/** - * TCP callback function if a connection (opened by tcp_connect/do_connect) has - * been established (or reset by the remote host). - * - * @see tcp.h (struct tcp_pcb.connected) for parameters and return values - */ -static err_t -do_connected(void *arg, struct tcp_pcb *pcb, err_t err) -{ - struct netconn *conn; - int was_blocking; - - LWIP_UNUSED_ARG(pcb); - - conn = (struct netconn *)arg; - - if (conn == NULL) { - return ERR_VAL; - } - - LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); - LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", - (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); - - if (conn->current_msg != NULL) { - conn->current_msg->err = err; - } - if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) { - setup_tcp(conn); - } - was_blocking = !IN_NONBLOCKING_CONNECT(conn); - SET_NONBLOCKING_CONNECT(conn, 0); - conn->current_msg = NULL; - conn->state = NETCONN_NONE; - if (!was_blocking) { - SYS_ARCH_DECL_PROTECT(lev); - SYS_ARCH_PROTECT(lev); - if (conn->last_err == ERR_INPROGRESS) { - conn->last_err = ERR_OK; - } - SYS_ARCH_UNPROTECT(lev); - } - API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); - - if (was_blocking) { - sys_sem_signal(&conn->op_completed); - } - return ERR_OK; -} -#endif /* LWIP_TCP */ - -/** - * Connect a pcb contained inside a netconn - * Called from netconn_connect. - * - * @param msg the api_msg_msg pointing to the connection and containing - * the IP address and port to connect to - */ -void -do_connect(struct api_msg_msg *msg) -{ - if (msg->conn->pcb.tcp == NULL) { - /* This may happen when calling netconn_connect() a second time */ - msg->err = ERR_CLSD; - } else { - switch (NETCONNTYPE_GROUP(msg->conn->type)) { -#if LWIP_RAW - case NETCONN_RAW: - msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); - break; -#endif /* LWIP_RAW */ -#if LWIP_UDP - case NETCONN_UDP: - msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case NETCONN_TCP: - /* Prevent connect while doing any other action. */ - if (msg->conn->state != NETCONN_NONE) { - msg->err = ERR_ISCONN; - } else { - setup_tcp(msg->conn); - msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, - msg->msg.bc.port, do_connected); - if (msg->err == ERR_OK) { - u8_t non_blocking = netconn_is_nonblocking(msg->conn); - msg->conn->state = NETCONN_CONNECT; - SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); - if (non_blocking) { - msg->err = ERR_INPROGRESS; - } else { - msg->conn->current_msg = msg; - /* sys_sem_signal() is called from do_connected (or err_tcp()), - * when the connection is established! */ - return; - } - } - } - break; -#endif /* LWIP_TCP */ - default: - LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0)); - break; - } - } - sys_sem_signal(&msg->conn->op_completed); -} - -/** - * Connect a pcb contained inside a netconn - * Only used for UDP netconns. - * Called from netconn_disconnect. - * - * @param msg the api_msg_msg pointing to the connection to disconnect - */ -void -do_disconnect(struct api_msg_msg *msg) -{ -#if LWIP_UDP - if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { - udp_disconnect(msg->conn->pcb.udp); - msg->err = ERR_OK; - } else -#endif /* LWIP_UDP */ - { - msg->err = ERR_VAL; - } - TCPIP_APIMSG_ACK(msg); -} - -#if LWIP_TCP -/** - * Set a TCP pcb contained in a netconn into listen mode - * Called from netconn_listen. - * - * @param msg the api_msg_msg pointing to the connection - */ -void -do_listen(struct api_msg_msg *msg) -{ - if (ERR_IS_FATAL(msg->conn->last_err)) { - msg->err = msg->conn->last_err; - } else { - msg->err = ERR_CONN; - if (msg->conn->pcb.tcp != NULL) { - if (msg->conn->type == NETCONN_TCP) { - if (msg->conn->state == NETCONN_NONE) { -#if TCP_LISTEN_BACKLOG - struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); -#else /* TCP_LISTEN_BACKLOG */ - struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp); -#endif /* TCP_LISTEN_BACKLOG */ - if (lpcb == NULL) { - /* in this case, the old pcb is still allocated */ - msg->err = ERR_MEM; - } else { - /* delete the recvmbox and allocate the acceptmbox */ - if (sys_mbox_valid(&msg->conn->recvmbox)) { - /** @todo: should we drain the recvmbox here? */ - sys_mbox_free(&msg->conn->recvmbox); - sys_mbox_set_invalid(&msg->conn->recvmbox); - } - msg->err = ERR_OK; - if (!sys_mbox_valid(&msg->conn->acceptmbox)) { - msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); - } - if (msg->err == ERR_OK) { - msg->conn->state = NETCONN_LISTEN; - msg->conn->pcb.tcp = lpcb; - tcp_arg(msg->conn->pcb.tcp, msg->conn); - tcp_accept(msg->conn->pcb.tcp, accept_function); - } else { - /* since the old pcb is already deallocated, free lpcb now */ - tcp_close(lpcb); - msg->conn->pcb.tcp = NULL; - } - } - } - } - } - } - TCPIP_APIMSG_ACK(msg); -} -#endif /* LWIP_TCP */ - -/** - * Send some data on a RAW or UDP pcb contained in a netconn - * Called from netconn_send - * - * @param msg the api_msg_msg pointing to the connection - */ -void -do_send(struct api_msg_msg *msg) -{ - if (ERR_IS_FATAL(msg->conn->last_err)) { - msg->err = msg->conn->last_err; - } else { - msg->err = ERR_CONN; - if (msg->conn->pcb.tcp != NULL) { - switch (NETCONNTYPE_GROUP(msg->conn->type)) { -#if LWIP_RAW - case NETCONN_RAW: - if (ip_addr_isany(&msg->msg.b->addr)) { - msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); - } else { - msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); - } - break; -#endif -#if LWIP_UDP - case NETCONN_UDP: -#if LWIP_CHECKSUM_ON_COPY - if (ip_addr_isany(&msg->msg.b->addr)) { - msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, - msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); - } else { - msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, - &msg->msg.b->addr, msg->msg.b->port, - msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); - } -#else /* LWIP_CHECKSUM_ON_COPY */ - if (ip_addr_isany(&msg->msg.b->addr)) { - msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); - } else { - msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); - } -#endif /* LWIP_CHECKSUM_ON_COPY */ - break; -#endif /* LWIP_UDP */ - default: - break; - } - } - } - TCPIP_APIMSG_ACK(msg); -} - -#if LWIP_TCP -/** - * Indicate data has been received from a TCP pcb contained in a netconn - * Called from netconn_recv - * - * @param msg the api_msg_msg pointing to the connection - */ -void -do_recv(struct api_msg_msg *msg) -{ - msg->err = ERR_OK; - if (msg->conn->pcb.tcp != NULL) { - if (msg->conn->type == NETCONN_TCP) { -#if TCP_LISTEN_BACKLOG - if (msg->conn->pcb.tcp->state == LISTEN) { - tcp_accepted(msg->conn->pcb.tcp); - } else -#endif /* TCP_LISTEN_BACKLOG */ - { - u32_t remaining = msg->msg.r.len; - do { - u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining; - tcp_recved(msg->conn->pcb.tcp, recved); - remaining -= recved; - }while(remaining != 0); - } - } - } - TCPIP_APIMSG_ACK(msg); -} - -/** - * See if more data needs to be written from a previous call to netconn_write. - * Called initially from do_write. If the first call can't send all data - * (because of low memory or empty send-buffer), this function is called again - * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the - * blocking application thread (waiting in netconn_write) is released. - * - * @param conn netconn (that is currently in state NETCONN_WRITE) to process - * @return ERR_OK - * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished - */ -static err_t -do_writemore(struct netconn *conn) -{ - err_t err = ERR_OK; - void *dataptr; - u16_t len, available; - u8_t write_finished = 0; - size_t diff; - u8_t dontblock = netconn_is_nonblocking(conn) || - (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK); - u8_t apiflags = conn->current_msg->msg.w.apiflags; - - LWIP_ASSERT("conn != NULL", conn != NULL); - LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); - LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); - LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); - LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", - conn->write_offset < conn->current_msg->msg.w.len); - - dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; - diff = conn->current_msg->msg.w.len - conn->write_offset; - if (diff > 0xffffUL) { /* max_u16_t */ - len = 0xffff; -#if LWIP_TCPIP_CORE_LOCKING - conn->flags |= NETCONN_FLAG_WRITE_DELAYED; -#endif - apiflags |= TCP_WRITE_FLAG_MORE; - } else { - len = (u16_t)diff; - } - available = tcp_sndbuf(conn->pcb.tcp); - if (available < len) { - /* don't try to write more than sendbuf */ - len = available; -#if LWIP_TCPIP_CORE_LOCKING - conn->flags |= NETCONN_FLAG_WRITE_DELAYED; -#endif - apiflags |= TCP_WRITE_FLAG_MORE; - } - if (dontblock && (len < conn->current_msg->msg.w.len)) { - /* failed to send all data at once -> nonblocking write not possible */ - err = ERR_MEM; - } - if (err == ERR_OK) { - LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); - err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); - } - if (dontblock && (err == ERR_MEM)) { - /* nonblocking write failed */ - write_finished = 1; - err = ERR_WOULDBLOCK; - /* let poll_tcp check writable space to mark the pcb - writable again */ - conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; - /* let select mark this pcb as non-writable. */ - API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); - } else { - /* if OK or memory error, check available space */ - if (((err == ERR_OK) || (err == ERR_MEM)) && - ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || - (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) { - /* The queued byte- or pbuf-count exceeds the configured low-water limit, - let select mark this pcb as non-writable. */ - API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); - } - - if (err == ERR_OK) { - conn->write_offset += len; - if (conn->write_offset == conn->current_msg->msg.w.len) { - /* everything was written */ - write_finished = 1; - conn->write_offset = 0; - } - tcp_output(conn->pcb.tcp); - } else if (err == ERR_MEM) { - /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called - we do NOT return to the application thread, since ERR_MEM is - only a temporary error! */ - - /* tcp_write returned ERR_MEM, try tcp_output anyway */ - tcp_output(conn->pcb.tcp); - - #if LWIP_TCPIP_CORE_LOCKING - conn->flags |= NETCONN_FLAG_WRITE_DELAYED; - #endif - } else { - /* On errors != ERR_MEM, we don't try writing any more but return - the error to the application thread. */ - write_finished = 1; - } - } - - if (write_finished) { - /* everything was written: set back connection state - and back to application task */ - conn->current_msg->err = err; - conn->current_msg = NULL; - conn->state = NETCONN_NONE; -#if LWIP_TCPIP_CORE_LOCKING - if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0) -#endif - { - sys_sem_signal(&conn->op_completed); - } - } -#if LWIP_TCPIP_CORE_LOCKING - else - return ERR_MEM; -#endif - return ERR_OK; -} -#endif /* LWIP_TCP */ - -/** - * Send some data on a TCP pcb contained in a netconn - * Called from netconn_write - * - * @param msg the api_msg_msg pointing to the connection - */ -void -do_write(struct api_msg_msg *msg) -{ - if (ERR_IS_FATAL(msg->conn->last_err)) { - msg->err = msg->conn->last_err; - } else { - if (msg->conn->type == NETCONN_TCP) { -#if LWIP_TCP - if (msg->conn->state != NETCONN_NONE) { - /* netconn is connecting, closing or in blocking write */ - msg->err = ERR_INPROGRESS; - } else if (msg->conn->pcb.tcp != NULL) { - msg->conn->state = NETCONN_WRITE; - /* set all the variables used by do_writemore */ - LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && - msg->conn->write_offset == 0); - LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); - msg->conn->current_msg = msg; - msg->conn->write_offset = 0; -#if LWIP_TCPIP_CORE_LOCKING - msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED; - if (do_writemore(msg->conn) != ERR_OK) { - LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); - UNLOCK_TCPIP_CORE(); - sys_arch_sem_wait(&msg->conn->op_completed, 0); - LOCK_TCPIP_CORE(); - LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); - } -#else /* LWIP_TCPIP_CORE_LOCKING */ - do_writemore(msg->conn); -#endif /* LWIP_TCPIP_CORE_LOCKING */ - /* for both cases: if do_writemore was called, don't ACK the APIMSG - since do_writemore ACKs it! */ - return; - } else { - msg->err = ERR_CONN; - } -#else /* LWIP_TCP */ - msg->err = ERR_VAL; -#endif /* LWIP_TCP */ -#if (LWIP_UDP || LWIP_RAW) - } else { - msg->err = ERR_VAL; -#endif /* (LWIP_UDP || LWIP_RAW) */ - } - } - TCPIP_APIMSG_ACK(msg); -} - -/** - * Return a connection's local or remote address - * Called from netconn_getaddr - * - * @param msg the api_msg_msg pointing to the connection - */ -void -do_getaddr(struct api_msg_msg *msg) -{ - if (msg->conn->pcb.ip != NULL) { - *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip : - msg->conn->pcb.ip->remote_ip); - - msg->err = ERR_OK; - switch (NETCONNTYPE_GROUP(msg->conn->type)) { -#if LWIP_RAW - case NETCONN_RAW: - if (msg->msg.ad.local) { - *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; - } else { - /* return an error as connecting is only a helper for upper layers */ - msg->err = ERR_CONN; - } - break; -#endif /* LWIP_RAW */ -#if LWIP_UDP - case NETCONN_UDP: - if (msg->msg.ad.local) { - *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; - } else { - if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { - msg->err = ERR_CONN; - } else { - *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; - } - } - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case NETCONN_TCP: - *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port); - break; -#endif /* LWIP_TCP */ - default: - LWIP_ASSERT("invalid netconn_type", 0); - break; - } - } else { - msg->err = ERR_CONN; - } - TCPIP_APIMSG_ACK(msg); -} - -/** - * Close a TCP pcb contained in a netconn - * Called from netconn_close - * - * @param msg the api_msg_msg pointing to the connection - */ -void -do_close(struct api_msg_msg *msg) -{ -#if LWIP_TCP - /* @todo: abort running write/connect? */ - if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) { - /* this only happens for TCP netconns */ - LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); - msg->err = ERR_INPROGRESS; - } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { - if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) { - /* LISTEN doesn't support half shutdown */ - msg->err = ERR_CONN; - } else { - if (msg->msg.sd.shut & NETCONN_SHUT_RD) { - /* Drain and delete mboxes */ - netconn_drain(msg->conn); - } - LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && - msg->conn->write_offset == 0); - msg->conn->state = NETCONN_CLOSE; - msg->conn->current_msg = msg; - do_close_internal(msg->conn); - /* for tcp netconns, do_close_internal ACKs the message */ - return; - } - } else -#endif /* LWIP_TCP */ - { - msg->err = ERR_VAL; - } - sys_sem_signal(&msg->conn->op_completed); -} - -#if LWIP_IGMP -/** - * Join multicast groups for UDP netconns. - * Called from netconn_join_leave_group - * - * @param msg the api_msg_msg pointing to the connection - */ -void -do_join_leave_group(struct api_msg_msg *msg) -{ - if (ERR_IS_FATAL(msg->conn->last_err)) { - msg->err = msg->conn->last_err; - } else { - if (msg->conn->pcb.tcp != NULL) { - if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { -#if LWIP_UDP - if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { - msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); - } else { - msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); - } -#endif /* LWIP_UDP */ -#if (LWIP_TCP || LWIP_RAW) - } else { - msg->err = ERR_VAL; -#endif /* (LWIP_TCP || LWIP_RAW) */ - } - } else { - msg->err = ERR_CONN; - } - } - TCPIP_APIMSG_ACK(msg); -} -#endif /* LWIP_IGMP */ - -#if LWIP_DNS -/** - * Callback function that is called when DNS name is resolved - * (or on timeout). A waiting application thread is waked up by - * signaling the semaphore. - */ -static void -do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) -{ - struct dns_api_msg *msg = (struct dns_api_msg*)arg; - - LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0); - LWIP_UNUSED_ARG(name); - - if (ipaddr == NULL) { - /* timeout or memory error */ - *msg->err = ERR_VAL; - } else { - /* address was resolved */ - *msg->err = ERR_OK; - *msg->addr = *ipaddr; - } - /* wake up the application task waiting in netconn_gethostbyname */ - sys_sem_signal(msg->sem); -} - -/** - * Execute a DNS query - * Called from netconn_gethostbyname - * - * @param arg the dns_api_msg pointing to the query - */ -void -do_gethostbyname(void *arg) -{ - struct dns_api_msg *msg = (struct dns_api_msg*)arg; - - *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg); - if (*msg->err != ERR_INPROGRESS) { - /* on error or immediate success, wake up the application - * task waiting in netconn_gethostbyname */ - sys_sem_signal(msg->sem); - } -} -#endif /* LWIP_DNS */ - -#endif /* LWIP_NETCONN */ diff --git a/tools/sdk/lwip/src/api/err.c b/tools/sdk/lwip/src/api/err.c deleted file mode 100644 index b0a4eb3e1..000000000 --- a/tools/sdk/lwip/src/api/err.c +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file - * Error Management module - * - */ - -/* - * 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 - * - */ - -#include "lwip/err.h" - -#ifdef LWIP_DEBUG - -static const char *err_strerr[] = { - "Ok.", /* ERR_OK 0 */ - "Out of memory error.", /* ERR_MEM -1 */ - "Buffer error.", /* ERR_BUF -2 */ - "Timeout.", /* ERR_TIMEOUT -3 */ - "Routing problem.", /* ERR_RTE -4 */ - "Operation in progress.", /* ERR_INPROGRESS -5 */ - "Illegal value.", /* ERR_VAL -6 */ - "Operation would block.", /* ERR_WOULDBLOCK -7 */ - "Connection aborted.", /* ERR_ABRT -8 */ - "Connection reset.", /* ERR_RST -9 */ - "Connection closed.", /* ERR_CLSD -10 */ - "Not connected.", /* ERR_CONN -11 */ - "Illegal argument.", /* ERR_ARG -12 */ - "Address in use.", /* ERR_USE -13 */ - "Low-level netif error.", /* ERR_IF -14 */ - "Already connected.", /* ERR_ISCONN -15 */ -}; - -/** - * Convert an lwip internal error to a string representation. - * - * @param err an lwip internal err_t - * @return a string representation for err - */ -const char * -lwip_strerr(err_t err) -{ - return err_strerr[-err]; - -} - -#endif /* LWIP_DEBUG */ diff --git a/tools/sdk/lwip/src/api/netbuf.c b/tools/sdk/lwip/src/api/netbuf.c deleted file mode 100644 index 886f66b05..000000000 --- a/tools/sdk/lwip/src/api/netbuf.c +++ /dev/null @@ -1,245 +0,0 @@ -/** - * @file - * Network buffer management - * - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" - -#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/netbuf.h" -#include "lwip/memp.h" - -#include - -/** - * Create (allocate) and initialize a new netbuf. - * The netbuf doesn't yet contain a packet buffer! - * ÉêÇëÒ»¸öеÄnetbuf¿Õ¼ä£¬µ«²»·ÖÅäÈκÎÊý¾Ý¿Õ¼ä - * @return a pointer to a new netbuf - * NULL on lack of memory - */ -struct -netbuf *netbuf_new(void) -{ - struct netbuf *buf; - - buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); - if (buf != NULL) { - 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; - } -} - -/** - * Deallocate a netbuf allocated by netbuf_new(). - * ÊÍ·ÅÒ»¸önetbuf¿Õ¼ä - * @param buf pointer to a netbuf allocated by netbuf_new() - */ -void -netbuf_delete(struct netbuf *buf) -{ - if (buf != NULL) { - if (buf->p != NULL) { - pbuf_free(buf->p); - buf->p = buf->ptr = NULL; - } - memp_free(MEMP_NETBUF, buf); - } -} - -/** - * Allocate memory for a packet buffer for a given netbuf. - *Ϊnetbuf½á¹¹·ÖÅäsize´óСµÄÊý¾Ý¿Õ¼ä - * @param buf the netbuf for which to allocate a packet buffer - * @param size the size of the packet buffer to allocate - * @return pointer to the allocated memory - * NULL if no memory could be allocated - */ -void * -netbuf_alloc(struct netbuf *buf, u16_t size) -{ - LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;); - - /* Deallocate any previously allocated memory. */ - if (buf->p != NULL) { - pbuf_free(buf->p); - } - buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); - if (buf->p == NULL) { - return NULL; - } - LWIP_ASSERT("check that first pbuf can hold size", - (buf->p->len >= size)); - buf->ptr = buf->p; - return buf->p->payload; -} - -/** - * Free the packet buffer included in a netbuf - *ÊÍ·Ånetbuf½á¹¹Ö¸ÏòµÄÊý¾Ýpbuf - * @param buf pointer to the netbuf which contains the packet buffer to free - */ -void -netbuf_free(struct netbuf *buf) -{ - LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); - if (buf->p != NULL) { - pbuf_free(buf->p); - } - buf->p = buf->ptr = NULL; -} - -/** - * Let a netbuf reference existing (non-volatile) data. - * - * @param buf netbuf which should reference the data - * @param dataptr pointer to the data to reference - * @param size size of the data - * @return ERR_OK if data is referenced - * ERR_MEM if data couldn't be referenced due to lack of memory - */ -err_t -netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size) -{ - LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;); - if (buf->p != NULL) { - pbuf_free(buf->p); - } - buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); - if (buf->p == NULL) { - buf->ptr = NULL; - return ERR_MEM; - } - buf->p->payload = (void*)dataptr; - buf->p->len = buf->p->tot_len = size; - buf->ptr = buf->p; - return ERR_OK; -} - -/** - * Chain one netbuf to another (@see pbuf_chain) - * - * @param head the first netbuf - * @param tail netbuf to chain after head, freed by this function, may not be reference after returning - */ -void -netbuf_chain(struct netbuf *head, struct netbuf *tail) -{ - LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;); - LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;); - pbuf_cat(head->p, tail->p); - head->ptr = head->p; - memp_free(MEMP_NETBUF, tail); -} - -/** - * 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 retreived, - * ERR_BUF on error. - */ -err_t -netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len) -{ - LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;); - LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;); - LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;); - - if (buf->ptr == NULL) { - return ERR_BUF; - } - *dataptr = buf->ptr->payload; - *len = buf->ptr->len; - return ERR_OK; -} - -/** - * Move the current data pointer of a packet buffer contained in a netbuf - * to the next part. - * The packet buffer itself is not modified. - * - * @param buf the netbuf to modify - * @return -1 if there is no next part - * 1 if moved to the next part but now there is no next part - * 0 if moved to the next part and there are still more parts - */ -s8_t -netbuf_next(struct netbuf *buf) -{ - LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;); - if (buf->ptr->next == NULL) { - return -1; - } - buf->ptr = buf->ptr->next; - if (buf->ptr->next == NULL) { - return 1; - } - return 0; -} - -/** - * 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. - * - * @param buf the netbuf to modify - */ -void -netbuf_first(struct netbuf *buf) -{ - LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); - buf->ptr = buf->p; -} - -#endif /* LWIP_NETCONN */ diff --git a/tools/sdk/lwip/src/api/netdb.c b/tools/sdk/lwip/src/api/netdb.c deleted file mode 100644 index a7e4e06bc..000000000 --- a/tools/sdk/lwip/src/api/netdb.c +++ /dev/null @@ -1,352 +0,0 @@ -/** - * @file - * API functions for name resolving - * - */ - -/* - * 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/netdb.h" - -#if LWIP_DNS && LWIP_SOCKET - -#include "lwip/err.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/ip_addr.h" -#include "lwip/api.h" -#include "lwip/dns.h" - -#include -#include - -/** helper struct for gethostbyname_r to access the char* buffer */ -struct gethostbyname_r_helper { - ip_addr_t *addrs; - ip_addr_t addr; - char *aliases; -}; - -/** h_errno is exported in netdb.h for access by applications. */ -#if LWIP_DNS_API_DECLARE_H_ERRNO -int h_errno; -#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ - -/** define "hostent" variables storage: 0 if we use a static (but unprotected) - * set of variables for lwip_gethostbyname, 1 if we use a local storage */ -#ifndef LWIP_DNS_API_HOSTENT_STORAGE -#define LWIP_DNS_API_HOSTENT_STORAGE 0 -#endif - -/** define "hostent" variables storage */ -#if LWIP_DNS_API_HOSTENT_STORAGE -#define HOSTENT_STORAGE -#else -#define HOSTENT_STORAGE static -#endif /* LWIP_DNS_API_STATIC_HOSTENT */ - -/** - * Returns an entry containing addresses of address family AF_INET - * for the host with name name. - * Due to dns_gethostbyname limitations, only one address is returned. - * - * @param name the hostname to resolve - * @return an entry containing addresses of address family AF_INET - * for the host with name name - */ -struct hostent* -lwip_gethostbyname(const char *name) -{ - err_t err; - ip_addr_t addr; - - /* buffer variables for lwip_gethostbyname() */ - HOSTENT_STORAGE struct hostent s_hostent; - HOSTENT_STORAGE char *s_aliases; - HOSTENT_STORAGE ip_addr_t s_hostent_addr; - HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2]; - - /* query host IP address */ - err = netconn_gethostbyname(name, &addr); - if (err != ERR_OK) { - LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); - h_errno = HOST_NOT_FOUND; - return NULL; - } - - /* fill hostent */ - s_hostent_addr = addr; - s_phostent_addr[0] = &s_hostent_addr; - s_phostent_addr[1] = NULL; - s_hostent.h_name = (char*)name; - s_hostent.h_aliases = &s_aliases; - s_hostent.h_addrtype = AF_INET; - s_hostent.h_length = sizeof(ip_addr_t); - s_hostent.h_addr_list = (char**)&s_phostent_addr; - -#if DNS_DEBUG - /* dump hostent */ - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name)); - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %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", s_hostent.h_addr_list)); - if (s_hostent.h_addr_list != NULL) { - u8_t idx; - for ( idx=0; s_hostent.h_addr_list[idx]; idx++) { - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx])); - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx]))); - } - } -#endif /* DNS_DEBUG */ - -#if LWIP_DNS_API_HOSTENT_STORAGE - /* this function should return the "per-thread" hostent after copy from s_hostent */ - return sys_thread_hostent(&s_hostent); -#else - return &s_hostent; -#endif /* LWIP_DNS_API_HOSTENT_STORAGE */ -} - -/** - * Thread-safe variant of lwip_gethostbyname: instead of using a static - * buffer, this function takes buffer and errno pointers as arguments - * and uses these for the result. - * - * @param name the hostname to resolve - * @param ret pre-allocated struct where to store the result - * @param buf pre-allocated buffer where to store additional data - * @param buflen the size of buf - * @param result pointer to a hostent pointer that is set to ret on success - * and set to zero on error - * @param h_errnop pointer to an int where to store errors (instead of modifying - * the global h_errno) - * @return 0 on success, non-zero on error, additional error information - * is stored in *h_errnop instead of h_errno to be thread-safe - */ -int -lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, - size_t buflen, struct hostent **result, int *h_errnop) -{ - err_t err; - struct gethostbyname_r_helper *h; - char *hostname; - size_t namelen; - int lh_errno; - - if (h_errnop == NULL) { - /* ensure h_errnop is never NULL */ - h_errnop = &lh_errno; - } - - if (result == NULL) { - /* not all arguments given */ - *h_errnop = EINVAL; - return -1; - } - /* first thing to do: set *result to nothing */ - *result = NULL; - if ((name == NULL) || (ret == NULL) || (buf == 0)) { - /* not all arguments given */ - *h_errnop = EINVAL; - return -1; - } - - namelen = strlen(name); - if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) { - /* buf can't hold the data needed + a copy of name */ - *h_errnop = ERANGE; - return -1; - } - - h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf); - hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper); - - /* query host IP address */ - 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 = ENSRNOTFOUND; - return -1; - } - - /* copy the hostname into buf */ - MEMCPY(hostname, name, namelen); - hostname[namelen] = 0; - - /* fill hostent */ - h->addrs = &(h->addr); - h->aliases = NULL; - 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->addrs); - - /* set result != NULL */ - *result = ret; - - /* return success */ - return 0; -} - -/** - * Frees one or more addrinfo structures returned by getaddrinfo(), along with - * any additional storage associated with those structures. If the ai_next field - * of the structure is not null, the entire list of structures is freed. - * - * @param ai struct addrinfo to free - */ -void -lwip_freeaddrinfo(struct addrinfo *ai) -{ - struct addrinfo *next; - - while (ai != NULL) { - next = ai->ai_next; - memp_free(MEMP_NETDB, ai); - ai = next; - } -} - -/** - * Translates the name of a service location (for example, a host name) and/or - * a service name and returns a set of socket addresses and associated - * information to be used in creating a socket with which to address the - * specified service. - * Memory for the result is allocated internally and must be freed by calling - * lwip_freeaddrinfo()! - * - * Due to a limitation in dns_gethostbyname, only the first address of a - * host is returned. - * Also, service names are not supported (only port numbers)! - * - * @param nodename descriptive name or address string of the host - * (may be NULL -> local address) - * @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 - */ -int -lwip_getaddrinfo(const char *nodename, const char *servname, - const struct addrinfo *hints, struct addrinfo **res) -{ - err_t err; - ip_addr_t addr; - struct addrinfo *ai; - struct sockaddr_in *sa = NULL; - int port_nr = 0; - size_t total_size; - size_t namelen = 0; - - if (res == NULL) { - return EAI_FAIL; - } - *res = NULL; - if ((nodename == NULL) && (servname == NULL)) { - return EAI_NONAME; - } - - if (servname != NULL) { - /* service name specified: convert to port number - * @todo?: currently, only ASCII integers (port numbers) are supported! */ - port_nr = atoi(servname); - if ((port_nr <= 0) || (port_nr > 0xffff)) { - return EAI_SERVICE; - } - } - - if (nodename != NULL) { - /* service location specified, try to resolve */ - err = netconn_gethostbyname(nodename, &addr); - if (err != ERR_OK) { - return EAI_FAIL; - } - } else { - /* service location specified, use loopback address */ - ip_addr_set_loopback(&addr); - } - - total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in); - if (nodename != NULL) { - namelen = strlen(nodename); - LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1); - total_size += namelen + 1; - } - /* If this fails, please report to lwip-devel! :-) */ - LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!", - total_size <= NETDB_ELEM_SIZE); - ai = (struct addrinfo *)memp_malloc(MEMP_NETDB); - if (ai == NULL) { - goto memerr; - } - memset(ai, 0, total_size); - 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; - ai->ai_protocol = hints->ai_protocol; - } - if (nodename != NULL) { - /* copy nodename to canonname if specified */ - 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_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 */ diff --git a/tools/sdk/lwip/src/api/netifapi.c b/tools/sdk/lwip/src/api/netifapi.c deleted file mode 100644 index 43e47203a..000000000 --- a/tools/sdk/lwip/src/api/netifapi.c +++ /dev/null @@ -1,160 +0,0 @@ -/** - * @file - * Network Interface Sequential API module - * - */ - -/* - * 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/opt.h" - -#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/netifapi.h" -#include "lwip/tcpip.h" - -/** - * Call netif_add() inside the tcpip_thread context. - */ -void -do_netifapi_netif_add(struct netifapi_msg_msg *msg) -{ - if (!netif_add( msg->netif, - msg->msg.add.ipaddr, - msg->msg.add.netmask, - msg->msg.add.gw, - msg->msg.add.state, - msg->msg.add.init, - msg->msg.add.input)) { - msg->err = ERR_IF; - } else { - msg->err = ERR_OK; - } - TCPIP_NETIFAPI_ACK(msg); -} - -/** - * Call netif_set_addr() inside the tcpip_thread context. - */ -void -do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg) -{ - netif_set_addr( msg->netif, - msg->msg.add.ipaddr, - msg->msg.add.netmask, - msg->msg.add.gw); - msg->err = ERR_OK; - TCPIP_NETIFAPI_ACK(msg); -} - -/** - * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the - * tcpip_thread context. - */ -void -do_netifapi_netif_common(struct netifapi_msg_msg *msg) -{ - if (msg->msg.common.errtfunc != NULL) { - msg->err = msg->msg.common.errtfunc(msg->netif); - } else { - msg->err = ERR_OK; - msg->msg.common.voidfunc(msg->netif); - } - TCPIP_NETIFAPI_ACK(msg); -} - -/** - * Call netif_add() in a thread-safe way by running that function inside the - * tcpip_thread context. - * - * @note for params @see netif_add() - */ -err_t -netifapi_netif_add(struct netif *netif, - ip_addr_t *ipaddr, - ip_addr_t *netmask, - ip_addr_t *gw, - void *state, - netif_init_fn init, - netif_input_fn input) -{ - 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; -} - -/** - * Call netif_set_addr() in a thread-safe way by running that function inside the - * tcpip_thread context. - * - * @note for params @see netif_set_addr() - */ -err_t -netifapi_netif_set_addr(struct netif *netif, - ip_addr_t *ipaddr, - ip_addr_t *netmask, - ip_addr_t *gw) -{ - struct netifapi_msg msg; - msg.function = do_netifapi_netif_set_addr; - msg.msg.netif = netif; - msg.msg.msg.add.ipaddr = ipaddr; - msg.msg.msg.add.netmask = netmask; - msg.msg.msg.add.gw = gw; - TCPIP_NETIFAPI(&msg); - return msg.msg.err; -} - -/** - * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe - * way by running that function inside the tcpip_thread context. - * - * @note use only for functions where there is only "netif" parameter. - */ -err_t -netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, - netifapi_errt_fn errtfunc) -{ - 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 */ diff --git a/tools/sdk/lwip/src/api/sockets.c b/tools/sdk/lwip/src/api/sockets.c deleted file mode 100644 index f3afd6306..000000000 --- a/tools/sdk/lwip/src/api/sockets.c +++ /dev/null @@ -1,2343 +0,0 @@ -/** - * @file - * Sockets BSD-Like API module - * - */ - -/* - * 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 - * - * Improved by Marc Boucher and David Haas - * - */ - -#include "lwip/opt.h" - -#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/sockets.h" -#include "lwip/api.h" -#include "lwip/sys.h" -#include "lwip/igmp.h" -#include "lwip/inet.h" -#include "lwip/tcp.h" -#include "lwip/raw.h" -#include "lwip/udp.h" -#include "lwip/tcpip.h" -#include "lwip/pbuf.h" -#if LWIP_CHECKSUM_ON_COPY -#include "lwip/inet_chksum.h" -#endif - -#include - -#define NUM_SOCKETS MEMP_NUM_NETCONN - -/** Contains all internal pointers and states used for a socket */ -struct lwip_sock { - /** sockets currently are built on netconns, each socket has one netconn */ - struct netconn *conn; - /** data that was left from the previous read */ - void *lastdata; - /** offset in the data that was left from the previous read */ - u16_t lastoffset; - /** number of times data was received, set by event_callback(), - tested by the receive and select functions */ - s16_t rcvevent; - /** number of times data was ACKed (free send buffer), set by event_callback(), - tested by select */ - u16_t sendevent; - /** error happened for this socket, set by event_callback(), tested by select */ - u16_t errevent; - /** last error that occurred on this socket */ - int err; - /** counter of how many threads are waiting for this socket using select */ - int select_waiting; -}; - -/** Description for a task waiting in select */ -struct lwip_select_cb { - /** Pointer to the next waiting task */ - struct lwip_select_cb *next; - /** Pointer to the previous waiting task */ - struct lwip_select_cb *prev; - /** readset passed to select */ - fd_set *readset; - /** writeset passed to select */ - fd_set *writeset; - /** unimplemented: exceptset passed to select */ - fd_set *exceptset; - /** don't signal the same semaphore twice: set to 1 when signalled */ - int sem_signalled; - /** semaphore to wake up a task waiting for select */ - sys_sem_t sem; -}; - -/** This struct is used to pass data to the set/getsockopt_internal - * functions running in tcpip_thread context (only a void* is allowed) */ -struct lwip_setgetsockopt_data { - /** socket struct for which to change options */ - struct lwip_sock *sock; -#ifdef LWIP_DEBUG - /** socket index for which to change options */ - int s; -#endif /* LWIP_DEBUG */ - /** level of the option to process */ - int level; - /** name of the option to process */ - int optname; - /** set: value to set the option to - * get: value of the option is stored here */ - void *optval; - /** size of *optval */ - socklen_t *optlen; - /** if an error occures, it is temporarily stored here */ - err_t err; -}; - -/** The global array of available sockets */ -static struct lwip_sock sockets[NUM_SOCKETS]; -/** The global list of tasks waiting for select */ -static struct lwip_select_cb *select_cb_list; -/** This counter is increased from lwip_select when the list is chagned - and checked in event_callback to see if it has changed. */ -static volatile int select_cb_ctr; - -/** Table to quickly map an lwIP error (err_t) to a socket error - * by using -err as an index */ -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. */ - ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */ - ECONNRESET, /* ERR_RST -9 Connection reset. */ - ESHUTDOWN, /* ERR_CLSD -10 Connection closed. */ - ENOTCONN, /* ERR_CONN -11 Not connected. */ - EIO, /* ERR_ARG -12 Illegal argument. */ - EADDRINUSE, /* ERR_USE -13 Address in use. */ - -1, /* ERR_IF -14 Low-level netif error */ - -1, /* ERR_ISCONN -15 Already connected. */ -}; - -#define ERR_TO_ERRNO_TABLE_SIZE \ - (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0])) - -#define err_to_errno(err) \ - ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \ - err_to_errno_table[-(err)] : EIO) - -#ifdef ERRNO -#ifndef set_errno -#define set_errno(err) errno = (err) -#endif -#else /* ERRNO */ -#define set_errno(err) -#endif /* ERRNO */ - -#define sock_set_errno(sk, e) do { \ - sk->err = (e); \ - set_errno(sk->err); \ -} while (0) - -/* Forward delcaration of some functions */ -static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); -static void lwip_getsockopt_internal(void *arg); -static void lwip_setsockopt_internal(void *arg); - -/** - * Initialize this module. This function has to be called before any other - * functions in this module! - */ -void -lwip_socket_init(void) -{ -} - -/** - * Map a externally used socket index to the internal socket representation. - * - * @param s externally used socket index - * @return struct lwip_sock for the socket or NULL if not found - */ -static struct lwip_sock * -get_socket(int s) -{ - struct lwip_sock *sock; - - if ((s < 0) || (s >= NUM_SOCKETS)) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s)); - set_errno(EBADF); - return NULL; - } - - sock = &sockets[s]; - - if (!sock->conn) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s)); - set_errno(EBADF); - return NULL; - } - - return sock; -} - -/** - * Same as get_socket but doesn't set errno - * - * @param s externally used socket index - * @return struct lwip_sock for the socket or NULL if not found - */ -static struct lwip_sock * -tryget_socket(int s) -{ - if ((s < 0) || (s >= NUM_SOCKETS)) { - return NULL; - } - if (!sockets[s].conn) { - return NULL; - } - return &sockets[s]; -} - -/** - * Allocate a new socket for a given netconn. - * - * @param newconn the netconn for which to allocate a socket - * @param accepted 1 if socket has been created by accept(), - * 0 if socket has been created by socket() - * @return the index of the new socket; -1 on error - */ -static int -alloc_socket(struct netconn *newconn, int accepted) -{ - int i; - SYS_ARCH_DECL_PROTECT(lev); - - /* allocate a new socket identifier */ - for (i = 0; i < NUM_SOCKETS; ++i) { - /* Protect socket array */ - SYS_ARCH_PROTECT(lev); - if (!sockets[i].conn) { - sockets[i].conn = newconn; - /* The socket is not yet known to anyone, so no need to protect - after having marked it as used. */ - SYS_ARCH_UNPROTECT(lev); - sockets[i].lastdata = NULL; - sockets[i].lastoffset = 0; - sockets[i].rcvevent = 0; - /* TCP sendbuf is empty, but the socket is not yet writable until connected - * (unless it has been created by accept()). */ - sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1); - sockets[i].errevent = 0; - sockets[i].err = 0; - sockets[i].select_waiting = 0; - return i; - } - SYS_ARCH_UNPROTECT(lev); - } - return -1; -} - -/** Free a socket. The socket's netconn must have been - * delete before! - * - * @param sock the socket to free - * @param is_tcp != 0 for TCP sockets, used to free lastdata - */ -static void -free_socket(struct lwip_sock *sock, int is_tcp) -{ - void *lastdata; - SYS_ARCH_DECL_PROTECT(lev); - - lastdata = sock->lastdata; - sock->lastdata = NULL; - sock->lastoffset = 0; - sock->err = 0; - - /* Protect socket array */ - SYS_ARCH_PROTECT(lev); - sock->conn = NULL; - SYS_ARCH_UNPROTECT(lev); - /* don't use 'sock' after this line, as another task might have allocated it */ - - if (lastdata != NULL) { - if (is_tcp) { - pbuf_free((struct pbuf *)lastdata); - } else { - netbuf_delete((struct netbuf *)lastdata); - } - } -} - -/* Below this, the well-known socket functions are implemented. - * Use google.com or opengroup.org to get a good description :-) - * - * Exceptions are documented! - */ - -int -lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) -{ - struct lwip_sock *sock, *nsock; - struct netconn *newconn; - ip_addr_t naddr; - u16_t port; - int newsock; - struct sockaddr_in sin; - err_t err; - SYS_ARCH_DECL_PROTECT(lev); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); - sock = get_socket(s); - if (!sock) { - return -1; - } - - if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); - sock_set_errno(sock, EWOULDBLOCK); - return -1; - } - - /* wait for a new connection */ - err = netconn_accept(sock->conn, &newconn); - if (err != ERR_OK) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - LWIP_ASSERT("newconn != NULL", newconn != NULL); - /* Prevent automatic window updates, we do this on our own! */ - netconn_set_noautorecved(newconn, 1); - - /* get the IP address and port of the remote host */ - err = netconn_peer(newconn, &naddr, &port); - if (err != ERR_OK) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); - netconn_delete(newconn); - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - - /* Note that POSIX only requires us to check addr is non-NULL. addrlen must - * not be NULL if addr is valid. - */ - if (NULL != addr) { - LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - inet_addr_from_ipaddr(&sin.sin_addr, &naddr); - - if (*addrlen > sizeof(sin)) - *addrlen = sizeof(sin); - - MEMCPY(addr, &sin, *addrlen); - } - - newsock = alloc_socket(newconn, 1); - if (newsock == -1) { - netconn_delete(newconn); - sock_set_errno(sock, ENFILE); - return -1; - } - LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS)); - LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback); - nsock = &sockets[newsock]; - - /* See event_callback: If data comes in right away after an accept, even - * though the server task might not have created a new socket yet. - * In that case, newconn->socket is counted down (newconn->socket--), - * so nsock->rcvevent is >= 1 here! - */ - SYS_ARCH_PROTECT(lev); - nsock->rcvevent += (s16_t)(-1 - newconn->socket); - newconn->socket = newsock; - SYS_ARCH_UNPROTECT(lev); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); - ip_addr_debug_print(SOCKETS_DEBUG, &naddr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); - - sock_set_errno(sock, 0); - return newsock; -} - -int -lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) -{ - struct lwip_sock *sock; - ip_addr_t local_addr; - u16_t local_port; - err_t err; - const struct sockaddr_in *name_in; - - sock = get_socket(s); - if (!sock) { - return -1; - } - - /* check size, familiy and alignment of 'name' */ - LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) && - ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), - sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - name_in = (const struct sockaddr_in *)(void*)name; - - inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr); - local_port = name_in->sin_port; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); - ip_addr_debug_print(SOCKETS_DEBUG, &local_addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port))); - - err = netconn_bind(sock->conn, &local_addr, ntohs(local_port)); - - if (err != ERR_OK) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); - sock_set_errno(sock, 0); - return 0; -} - -int -lwip_close(int s) -{ - struct lwip_sock *sock; - int is_tcp = 0; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); - - sock = get_socket(s); - if (!sock) { - return -1; - } - - if(sock->conn != NULL) { - is_tcp = netconn_type(sock->conn) == NETCONN_TCP; - } else { - LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL); - } - - netconn_delete(sock->conn); - - free_socket(sock, is_tcp); - set_errno(0); - return 0; -} - -int -lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) -{ - struct lwip_sock *sock; - err_t err; - const struct sockaddr_in *name_in; - - sock = get_socket(s); - if (!sock) { - return -1; - } - - /* check size, familiy and alignment of 'name' */ - LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) && - ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), - sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - name_in = (const struct sockaddr_in *)(void*)name; - - if (name_in->sin_family == AF_UNSPEC) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); - err = netconn_disconnect(sock->conn); - } else { - ip_addr_t remote_addr; - u16_t remote_port; - - inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr); - remote_port = name_in->sin_port; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); - ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port))); - - err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); - } - - if (err != ERR_OK) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); - sock_set_errno(sock, 0); - return 0; -} - -/** - * Set a socket into listen mode. - * The socket may not have been used for another connection previously. - * - * @param s the socket to set to listening mode - * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) - * @return 0 on success, non-zero on failure - */ -int -lwip_listen(int s, int backlog) -{ - struct lwip_sock *sock; - err_t err; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); - - sock = get_socket(s); - if (!sock) { - return -1; - } - - /* limit the "backlog" parameter to fit in an u8_t */ - backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); - - err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); - - if (err != ERR_OK) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - - sock_set_errno(sock, 0); - return 0; -} - -int -lwip_recvfrom(int s, void *mem, size_t len, int flags, - struct sockaddr *from, socklen_t *fromlen) -{ - struct lwip_sock *sock; - void *buf = NULL; - struct pbuf *p; - u16_t buflen, copylen; - int off = 0; - ip_addr_t *addr; - u16_t port; - u8_t done = 0; - err_t err; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); - sock = get_socket(s); - if (!sock) { - return -1; - } - - do { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata)); - /* Check if there is data left from the last recv operation. */ - if (sock->lastdata) { - buf = sock->lastdata; - } else { - /* If this is non-blocking call, then check first */ - if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && - (sock->rcvevent <= 0)) { - if (off > 0) { - /* update receive window */ - netconn_recved(sock->conn, (u32_t)off); - /* already received data, return that */ - sock_set_errno(sock, 0); - return off; - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); - sock_set_errno(sock, EWOULDBLOCK); - return -1; - } - - /* No data was left from the previous operation, so we try to get - some from the network. */ - if (netconn_type(sock->conn) == NETCONN_TCP) { - err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf); - } else { - err = netconn_recv(sock->conn, (struct netbuf **)&buf); - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n", - err, buf)); - - if (err != ERR_OK) { - if (off > 0) { - /* update receive window */ - netconn_recved(sock->conn, (u32_t)off); - /* already received data, return that */ - sock_set_errno(sock, 0); - return off; - } - /* We should really do some error checking here. */ - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n", - s, lwip_strerr(err))); - sock_set_errno(sock, err_to_errno(err)); - if (err == ERR_CLSD) { - return 0; - } else { - return -1; - } - } - LWIP_ASSERT("buf != NULL", buf != NULL); - sock->lastdata = buf; - } - - if (netconn_type(sock->conn) == NETCONN_TCP) { - p = (struct pbuf *)buf; - } else { - p = ((struct netbuf *)buf)->p; - } - buflen = p->tot_len; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n", - buflen, len, off, sock->lastoffset)); - - buflen -= sock->lastoffset; - - if (len > buflen) { - copylen = buflen; - } else { - copylen = (u16_t)len; - } - - /* copy the contents of the received buffer into - the supplied memory pointer mem */ - pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset); - - off += copylen; - - if (netconn_type(sock->conn) == NETCONN_TCP) { - LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); - len -= copylen; - if ( (len <= 0) || - (p->flags & PBUF_FLAG_PUSH) || - (sock->rcvevent <= 0) || - ((flags & MSG_PEEK)!=0)) { - done = 1; - } - } else { - done = 1; - } - - /* Check to see from where the data was.*/ - if (done) { - ip_addr_t fromaddr; - if (from && fromlen) { - struct sockaddr_in sin; - - if (netconn_type(sock->conn) == NETCONN_TCP) { - addr = &fromaddr; - netconn_getaddr(sock->conn, addr, &port, 0); - } else { - addr = netbuf_fromaddr((struct netbuf *)buf); - port = netbuf_fromport((struct netbuf *)buf); - } - - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - inet_addr_from_ipaddr(&sin.sin_addr, addr); - - if (*fromlen > sizeof(sin)) { - *fromlen = sizeof(sin); - } - - MEMCPY(from, &sin, *fromlen); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); - ip_addr_debug_print(SOCKETS_DEBUG, addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); - } else { -#if SOCKETS_DEBUG - if (netconn_type(sock->conn) == NETCONN_TCP) { - addr = &fromaddr; - netconn_getaddr(sock->conn, addr, &port, 0); - } else { - addr = netbuf_fromaddr((struct netbuf *)buf); - port = netbuf_fromport((struct netbuf *)buf); - } - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); - ip_addr_debug_print(SOCKETS_DEBUG, addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); -#endif /* SOCKETS_DEBUG */ - } - } - - /* If we don't peek the incoming message... */ - if ((flags & MSG_PEEK) == 0) { - /* If this is a TCP socket, check if there is data left in the - buffer. If so, it should be saved in the sock structure for next - time around. */ - if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) { - sock->lastdata = buf; - sock->lastoffset += copylen; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf)); - } else { - sock->lastdata = NULL; - sock->lastoffset = 0; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf)); - if (netconn_type(sock->conn) == NETCONN_TCP) { - pbuf_free((struct pbuf *)buf); - } else { - netbuf_delete((struct netbuf *)buf); - } - } - } - } while (!done); - - if (off > 0) { - /* update receive window */ - netconn_recved(sock->conn, (u32_t)off); - } - sock_set_errno(sock, 0); - return off; -} - -int -lwip_read(int s, void *mem, size_t len) -{ - return lwip_recvfrom(s, mem, len, 0, NULL, NULL); -} - -int -lwip_recv(int s, void *mem, size_t len, int flags) -{ - return lwip_recvfrom(s, mem, len, flags, NULL, NULL); -} - -int -lwip_send(int s, const void *data, size_t size, int flags) -{ - struct lwip_sock *sock; - err_t err; - u8_t write_flags; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", - s, data, size, flags)); - - sock = get_socket(s); - if (!sock) { - return -1; - } - - if (sock->conn->type != NETCONN_TCP) { -#if (LWIP_UDP || LWIP_RAW) - return lwip_sendto(s, data, size, flags, NULL, 0); -#else /* (LWIP_UDP || LWIP_RAW) */ - sock_set_errno(sock, err_to_errno(ERR_ARG)); - return -1; -#endif /* (LWIP_UDP || LWIP_RAW) */ - } - - if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) { - if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) { - /* too much data to ever send nonblocking! */ - sock_set_errno(sock, EMSGSIZE); - return -1; - } - } - - write_flags = NETCONN_COPY | - ((flags & MSG_MORE) ? NETCONN_MORE : 0) | - ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); - err = netconn_write(sock->conn, data, size, write_flags); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size)); - sock_set_errno(sock, err_to_errno(err)); - return (err == ERR_OK ? (int)size : -1); -} - -int -lwip_sendto(int s, const void *data, size_t size, int flags, - const struct sockaddr *to, socklen_t tolen) -{ - struct lwip_sock *sock; - err_t err; - u16_t short_size; - const struct sockaddr_in *to_in; - u16_t remote_port; -#if !LWIP_TCPIP_CORE_LOCKING - struct netbuf buf; -#endif - - sock = get_socket(s); - if (!sock) { - return -1; - } - - if (sock->conn->type == NETCONN_TCP) { -#if LWIP_TCP - return lwip_send(s, data, size, flags); -#else /* LWIP_TCP */ - LWIP_UNUSED_ARG(flags); - sock_set_errno(sock, err_to_errno(ERR_ARG)); - return -1; -#endif /* LWIP_TCP */ - } - - /* @todo: split into multiple sendto's? */ - LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); - short_size = (u16_t)size; - LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || - ((tolen == sizeof(struct sockaddr_in)) && - ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))), - sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - to_in = (const struct sockaddr_in *)(void*)to; - -#if LWIP_TCPIP_CORE_LOCKING - /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */ - { - struct pbuf* p; - ip_addr_t *remote_addr; - -#if LWIP_NETIF_TX_SINGLE_PBUF - p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM); - if (p != NULL) { -#if LWIP_CHECKSUM_ON_COPY - u16_t chksum = 0; - if (sock->conn->type != NETCONN_RAW) { - chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size); - } else -#endif /* LWIP_CHECKSUM_ON_COPY */ - MEMCPY(p->payload, data, size); -#else /* LWIP_NETIF_TX_SINGLE_PBUF */ - p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF); - if (p != NULL) { - p->payload = (void*)data; -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - - if (to_in != NULL) { - inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr); - remote_port = ntohs(to_in->sin_port); - } else { - remote_addr = IP_ADDR_ANY; - remote_port = 0; - } - - LOCK_TCPIP_CORE(); - if (sock->conn->type == NETCONN_RAW) { - err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr); - } else { -#if LWIP_UDP -#if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF - err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p, - remote_addr, remote_port, 1, chksum); -#else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ - err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p, - remote_addr, remote_port); -#endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ -#else /* LWIP_UDP */ - err = ERR_ARG; -#endif /* LWIP_UDP */ - } - UNLOCK_TCPIP_CORE(); - - pbuf_free(p); - } else { - err = ERR_MEM; - } - } -#else /* LWIP_TCPIP_CORE_LOCKING */ - /* initialize a buffer */ - buf.p = buf.ptr = NULL; -#if LWIP_CHECKSUM_ON_COPY - buf.flags = 0; -#endif /* LWIP_CHECKSUM_ON_COPY */ - if (to) { - inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr); - remote_port = ntohs(to_in->sin_port); - netbuf_fromport(&buf) = remote_port; - } else { - remote_port = 0; - ip_addr_set_any(&buf.addr); - netbuf_fromport(&buf) = 0; - } - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%d"U16_F", flags=0x%x to=", - s, data, short_size, flags)); - ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); - - /* make the buffer point to the data that should be sent */ -#if LWIP_NETIF_TX_SINGLE_PBUF - /* Allocate a new netbuf and copy the data into it. */ - if (netbuf_alloc(&buf, short_size) == NULL) { - err = ERR_MEM; - } else { -#if LWIP_CHECKSUM_ON_COPY - if (sock->conn->type != NETCONN_RAW) { - u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); - netbuf_set_chksum(&buf, chksum); - err = ERR_OK; - } else -#endif /* LWIP_CHECKSUM_ON_COPY */ - { - err = netbuf_take(&buf, data, short_size); - } - } -#else /* LWIP_NETIF_TX_SINGLE_PBUF */ - err = netbuf_ref(&buf, data, short_size); -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - if (err == ERR_OK) { - /* send the data */ - err = netconn_send(sock->conn, &buf); - } - - /* deallocated the buffer */ - netbuf_free(&buf); -#endif /* LWIP_TCPIP_CORE_LOCKING */ - sock_set_errno(sock, err_to_errno(err)); - return (err == ERR_OK ? short_size : -1); -} - -int -lwip_socket(int domain, int type, int protocol) -{ - struct netconn *conn; - int i; - - LWIP_UNUSED_ARG(domain); - - /* create a netconn */ - switch (type) { - case SOCK_RAW: - conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", - domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); - break; - case SOCK_DGRAM: - conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ? - NETCONN_UDPLITE : NETCONN_UDP, event_callback); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", - domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); - break; - case SOCK_STREAM: - conn = netconn_new_with_callback(NETCONN_TCP, event_callback); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", - domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); - if (conn != NULL) { - /* Prevent automatic window updates, we do this on our own! */ - netconn_set_noautorecved(conn, 1); - } - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", - domain, type, protocol)); - set_errno(EINVAL); - return -1; - } - - if (!conn) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); - set_errno(ENOBUFS); - return -1; - } - - i = alloc_socket(conn, 0); - - if (i == -1) { - netconn_delete(conn); - set_errno(ENFILE); - return -1; - } - conn->socket = i; - LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); - set_errno(0); - return i; -} - -int -lwip_write(int s, const void *data, size_t size) -{ - return lwip_send(s, data, size, 0); -} - -/** - * Go through the readset and writeset lists and see which socket of the sockets - * set in the sets has events. On return, readset, writeset and exceptset have - * the sockets enabled that had events. - * - * exceptset is not used for now!!! - * - * @param maxfdp1 the highest socket index in the sets - * @param readset_in: set of sockets to check for read events - * @param writeset_in: set of sockets to check for write events - * @param exceptset_in: set of sockets to check for error events - * @param readset_out: set of sockets that had read events - * @param writeset_out: set of sockets that had write events - * @param exceptset_out: set os sockets that had error events - * @return number of sockets that had events (read/write/exception) (>= 0) - */ -static int -lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, - fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) -{ - int i, nready = 0; - fd_set lreadset, lwriteset, lexceptset; - struct lwip_sock *sock; - SYS_ARCH_DECL_PROTECT(lev); - - FD_ZERO(&lreadset); - FD_ZERO(&lwriteset); - FD_ZERO(&lexceptset); - - /* Go through each socket in each list to count number of sockets which - currently match */ - for(i = 0; i < maxfdp1; i++) { - void* lastdata = NULL; - s16_t rcvevent = 0; - u16_t sendevent = 0; - u16_t errevent = 0; - /* First get the socket's status (protected)... */ - SYS_ARCH_PROTECT(lev); - sock = tryget_socket(i); - if (sock != NULL) { - lastdata = sock->lastdata; - rcvevent = sock->rcvevent; - sendevent = sock->sendevent; - errevent = sock->errevent; - } - SYS_ARCH_UNPROTECT(lev); - /* ... then examine it: */ - /* See if netconn of this socket is ready for read */ - if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { - FD_SET(i, &lreadset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); - nready++; - } - /* See if netconn of this socket is ready for write */ - if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { - FD_SET(i, &lwriteset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); - nready++; - } - /* See if netconn of this socket had an error */ - if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { - FD_SET(i, &lexceptset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); - nready++; - } - } - /* copy local sets to the ones provided as arguments */ - *readset_out = lreadset; - *writeset_out = lwriteset; - *exceptset_out = lexceptset; - - LWIP_ASSERT("nready >= 0", nready >= 0); - return nready; -} - -/** - * Processing exceptset is not yet implemented. - */ -int -lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, - struct timeval *timeout) -{ - u32_t waitres = 0; - int nready; - fd_set lreadset, lwriteset, lexceptset; - u32_t msectimeout; - struct lwip_select_cb select_cb; - err_t err; - int i; - SYS_ARCH_DECL_PROTECT(lev); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", - maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, - timeout ? (s32_t)timeout->tv_sec : (s32_t)-1, - timeout ? (s32_t)timeout->tv_usec : (s32_t)-1)); - - /* Go through each socket in each list to count number of sockets which - currently match */ - nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); - - /* If we don't have any current events, then suspend if we are supposed to */ - if (!nready) { - if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); - /* This is OK as the local fdsets are empty and nready is zero, - or we would have returned earlier. */ - goto return_copy_fdsets; - } - - /* None ready: add our semaphore to list: - We don't actually need any dynamic memory. Our entry on the - list is only valid while we are in this function, so it's ok - to use local variables. */ - - select_cb.next = NULL; - select_cb.prev = NULL; - select_cb.readset = readset; - select_cb.writeset = writeset; - select_cb.exceptset = exceptset; - select_cb.sem_signalled = 0; - err = sys_sem_new(&select_cb.sem, 0); - if (err != ERR_OK) { - /* failed to create semaphore */ - set_errno(ENOMEM); - return -1; - } - - /* Protect the select_cb_list */ - SYS_ARCH_PROTECT(lev); - - /* Put this select_cb on top of list */ - select_cb.next = select_cb_list; - if (select_cb_list != NULL) { - select_cb_list->prev = &select_cb; - } - select_cb_list = &select_cb; - /* Increasing this counter tells even_callback that the list has changed. */ - select_cb_ctr++; - - /* Now we can safely unprotect */ - SYS_ARCH_UNPROTECT(lev); - - /* Increase select_waiting for each socket we are interested in */ - for(i = 0; i < maxfdp1; i++) { - if ((readset && FD_ISSET(i, readset)) || - (writeset && FD_ISSET(i, writeset)) || - (exceptset && FD_ISSET(i, exceptset))) { - struct lwip_sock *sock = tryget_socket(i); - LWIP_ASSERT("sock != NULL", sock != NULL); - SYS_ARCH_PROTECT(lev); - sock->select_waiting++; - LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); - SYS_ARCH_UNPROTECT(lev); - } - } - - /* Call lwip_selscan again: there could have been events between - the last scan (whithout us on the list) and putting us on the list! */ - nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); - if (!nready) { - /* Still none ready, just wait to be woken */ - if (timeout == 0) { - /* Wait forever */ - msectimeout = 0; - } else { - msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); - if (msectimeout == 0) { - /* Wait 1ms at least (0 means wait forever) */ - msectimeout = 1; - } - } - - waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout); - } - /* Increase select_waiting for each socket we are interested in */ - for(i = 0; i < maxfdp1; i++) { - if ((readset && FD_ISSET(i, readset)) || - (writeset && FD_ISSET(i, writeset)) || - (exceptset && FD_ISSET(i, exceptset))) { - struct lwip_sock *sock = tryget_socket(i); - LWIP_ASSERT("sock != NULL", sock != NULL); - SYS_ARCH_PROTECT(lev); - sock->select_waiting--; - LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0); - SYS_ARCH_UNPROTECT(lev); - } - } - /* Take us off the list */ - SYS_ARCH_PROTECT(lev); - if (select_cb.next != NULL) { - select_cb.next->prev = select_cb.prev; - } - if (select_cb_list == &select_cb) { - LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL); - select_cb_list = select_cb.next; - } else { - LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL); - select_cb.prev->next = select_cb.next; - } - /* Increasing this counter tells even_callback that the list has changed. */ - select_cb_ctr++; - SYS_ARCH_UNPROTECT(lev); - - sys_sem_free(&select_cb.sem); - if (waitres == SYS_ARCH_TIMEOUT) { - /* Timeout */ - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); - /* This is OK as the local fdsets are empty and nready is zero, - or we would have returned earlier. */ - goto return_copy_fdsets; - } - - /* See what's set */ - nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); - } - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); -return_copy_fdsets: - set_errno(0); - if (readset) { - *readset = lreadset; - } - if (writeset) { - *writeset = lwriteset; - } - if (exceptset) { - *exceptset = lexceptset; - } - - - return nready; -} - -/** - * Callback registered in the netconn layer for each socket-netconn. - * Processes recvevent (data available) and wakes up tasks waiting for select. - */ -static void -event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) -{ - int s; - struct lwip_sock *sock; - struct lwip_select_cb *scb; - int last_select_cb_ctr; - SYS_ARCH_DECL_PROTECT(lev); - - LWIP_UNUSED_ARG(len); - - /* Get socket */ - if (conn) { - s = conn->socket; - if (s < 0) { - /* Data comes in right away after an accept, even though - * the server task might not have created a new socket yet. - * Just count down (or up) if that's the case and we - * will use the data later. Note that only receive events - * can happen before the new socket is set up. */ - SYS_ARCH_PROTECT(lev); - if (conn->socket < 0) { - if (evt == NETCONN_EVT_RCVPLUS) { - conn->socket--; - } - SYS_ARCH_UNPROTECT(lev); - return; - } - s = conn->socket; - SYS_ARCH_UNPROTECT(lev); - } - - sock = get_socket(s); - if (!sock) { - return; - } - } else { - return; - } - - SYS_ARCH_PROTECT(lev); - /* Set event as required */ - switch (evt) { - case NETCONN_EVT_RCVPLUS: - sock->rcvevent++; - break; - case NETCONN_EVT_RCVMINUS: - sock->rcvevent--; - break; - case NETCONN_EVT_SENDPLUS: - sock->sendevent = 1; - break; - case NETCONN_EVT_SENDMINUS: - sock->sendevent = 0; - break; - case NETCONN_EVT_ERROR: - sock->errevent = 1; - break; - default: - LWIP_ASSERT("unknown event", 0); - break; - } - - if (sock->select_waiting == 0) { - /* noone is waiting for this socket, no need to check select_cb_list */ - SYS_ARCH_UNPROTECT(lev); - return; - } - - /* Now decide if anyone is waiting for this socket */ - /* NOTE: This code goes through the select_cb_list list multiple times - ONLY IF a select was actually waiting. We go through the list the number - of waiting select calls + 1. This list is expected to be small. */ - - /* At this point, SYS_ARCH is still protected! */ -again: - for (scb = select_cb_list; scb != NULL; scb = scb->next) { - if (scb->sem_signalled == 0) { - /* semaphore not signalled yet */ - int do_signal = 0; - /* Test this select call for our socket */ - if (sock->rcvevent > 0) { - if (scb->readset && FD_ISSET(s, scb->readset)) { - do_signal = 1; - } - } - if (sock->sendevent != 0) { - if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { - do_signal = 1; - } - } - if (sock->errevent != 0) { - if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { - do_signal = 1; - } - } - if (do_signal) { - scb->sem_signalled = 1; - /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might - lead to the select thread taking itself off the list, invalidagin the semaphore. */ - sys_sem_signal(&scb->sem); - } - } - /* unlock interrupts with each step */ - last_select_cb_ctr = select_cb_ctr; - SYS_ARCH_UNPROTECT(lev); - /* this makes sure interrupt protection time is short */ - SYS_ARCH_PROTECT(lev); - if (last_select_cb_ctr != select_cb_ctr) { - /* someone has changed select_cb_list, restart at the beginning */ - goto again; - } - } - SYS_ARCH_UNPROTECT(lev); -} - -/** - * Unimplemented: Close one end of a full-duplex connection. - * Currently, the full connection is closed. - */ -int -lwip_shutdown(int s, int how) -{ - struct lwip_sock *sock; - err_t err; - u8_t shut_rx = 0, shut_tx = 0; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); - - sock = get_socket(s); - if (!sock) { - return -1; - } - - if (sock->conn != NULL) { - if (netconn_type(sock->conn) != NETCONN_TCP) { - sock_set_errno(sock, EOPNOTSUPP); - return EOPNOTSUPP; - } - } else { - sock_set_errno(sock, ENOTCONN); - return ENOTCONN; - } - - if (how == SHUT_RD) { - shut_rx = 1; - } else if (how == SHUT_WR) { - shut_tx = 1; - } else if(how == SHUT_RDWR) { - shut_rx = 1; - shut_tx = 1; - } else { - sock_set_errno(sock, EINVAL); - return EINVAL; - } - err = netconn_shutdown(sock->conn, shut_rx, shut_tx); - - sock_set_errno(sock, err_to_errno(err)); - return (err == ERR_OK ? 0 : -1); -} - -static int -lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) -{ - struct lwip_sock *sock; - struct sockaddr_in sin; - ip_addr_t naddr; - - sock = get_socket(s); - if (!sock) { - return -1; - } - - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - - /* get the IP address and port */ - netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local); - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); - ip_addr_debug_print(SOCKETS_DEBUG, &naddr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port)); - - sin.sin_port = htons(sin.sin_port); - inet_addr_from_ipaddr(&sin.sin_addr, &naddr); - - if (*namelen > sizeof(sin)) { - *namelen = sizeof(sin); - } - - MEMCPY(name, &sin, *namelen); - sock_set_errno(sock, 0); - return 0; -} - -int -lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) -{ - return lwip_getaddrname(s, name, namelen, 0); -} - -int -lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) -{ - return lwip_getaddrname(s, name, namelen, 1); -} - -int -lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) -{ - err_t err = ERR_OK; - struct lwip_sock *sock = get_socket(s); - struct lwip_setgetsockopt_data data; - - if (!sock) { - return -1; - } - - if ((NULL == optval) || (NULL == optlen)) { - sock_set_errno(sock, EFAULT); - return -1; - } - - /* Do length and type checks for the various options first, to keep it readable. */ - switch (level) { - -/* Level: SOL_SOCKET */ - case SOL_SOCKET: - switch (optname) { - - case SO_ACCEPTCONN: - case SO_BROADCAST: - /* UNIMPL case SO_DEBUG: */ - /* UNIMPL case SO_DONTROUTE: */ - case SO_ERROR: - case SO_KEEPALIVE: - /* UNIMPL case SO_CONTIMEO: */ - /* UNIMPL case SO_SNDTIMEO: */ -#if LWIP_SO_RCVTIMEO - case SO_RCVTIMEO: -#endif /* LWIP_SO_RCVTIMEO */ -#if LWIP_SO_RCVBUF - case SO_RCVBUF: -#endif /* LWIP_SO_RCVBUF */ - /* UNIMPL case SO_OOBINLINE: */ - /* UNIMPL case SO_SNDBUF: */ - /* UNIMPL case SO_RCVLOWAT: */ - /* UNIMPL case SO_SNDLOWAT: */ -#if SO_REUSE - case SO_REUSEADDR: - case SO_REUSEPORT: -#endif /* SO_REUSE */ - case SO_TYPE: - /* UNIMPL case SO_USELOOPBACK: */ - if (*optlen < sizeof(int)) { - err = EINVAL; - } - break; - - case SO_NO_CHECK: - if (*optlen < sizeof(int)) { - err = EINVAL; - } -#if LWIP_UDP - if ((sock->conn->type != NETCONN_UDP) || - ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { - /* this flag is only available for UDP, not for UDP lite */ - err = EAFNOSUPPORT; - } -#endif /* LWIP_UDP */ - break; - - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - } /* switch (optname) */ - break; - -/* Level: IPPROTO_IP */ - case IPPROTO_IP: - switch (optname) { - /* UNIMPL case IP_HDRINCL: */ - /* UNIMPL case IP_RCVDSTADDR: */ - /* UNIMPL case IP_RCVIF: */ - case IP_TTL: - case IP_TOS: - if (*optlen < sizeof(int)) { - err = EINVAL; - } - break; -#if LWIP_IGMP - case IP_MULTICAST_TTL: - if (*optlen < sizeof(u8_t)) { - err = EINVAL; - } - break; - case IP_MULTICAST_IF: - if (*optlen < sizeof(struct in_addr)) { - err = EINVAL; - } - break; - case IP_MULTICAST_LOOP: - if (*optlen < sizeof(u8_t)) { - err = EINVAL; - } - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { - err = EAFNOSUPPORT; - } - break; -#endif /* LWIP_IGMP */ - - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - } /* switch (optname) */ - break; - -#if LWIP_TCP -/* Level: IPPROTO_TCP */ - case IPPROTO_TCP: - if (*optlen < sizeof(int)) { - err = EINVAL; - break; - } - - /* If this is no TCP socket, ignore any options. */ - if (sock->conn->type != NETCONN_TCP) - return 0; - - switch (optname) { - case TCP_NODELAY: - case TCP_KEEPALIVE: -#if LWIP_TCP_KEEPALIVE - case TCP_KEEPIDLE: - case TCP_KEEPINTVL: - case TCP_KEEPCNT: -#endif /* LWIP_TCP_KEEPALIVE */ - break; - - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - } /* switch (optname) */ - break; -#endif /* LWIP_TCP */ -#if LWIP_UDP && LWIP_UDPLITE -/* Level: IPPROTO_UDPLITE */ - case IPPROTO_UDPLITE: - if (*optlen < sizeof(int)) { - err = EINVAL; - break; - } - - /* If this is no UDP lite socket, ignore any options. */ - if (sock->conn->type != NETCONN_UDPLITE) { - return 0; - } - - switch (optname) { - case UDPLITE_SEND_CSCOV: - case UDPLITE_RECV_CSCOV: - break; - - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - } /* switch (optname) */ - break; -#endif /* LWIP_UDP && LWIP_UDPLITE*/ -/* UNDEFINED LEVEL */ - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", - s, level, optname)); - err = ENOPROTOOPT; - } /* switch */ - - - if (err != ERR_OK) { - sock_set_errno(sock, err); - return -1; - } - - /* Now do the actual option processing */ - data.sock = sock; -#ifdef LWIP_DEBUG - data.s = s; -#endif /* LWIP_DEBUG */ - data.level = level; - data.optname = optname; - data.optval = optval; - data.optlen = optlen; - data.err = err; - tcpip_callback(lwip_getsockopt_internal, &data); - sys_arch_sem_wait(&sock->conn->op_completed, 0); - /* maybe lwip_getsockopt_internal has changed err */ - err = data.err; - - sock_set_errno(sock, err); - return err ? -1 : 0; -} - -static void -lwip_getsockopt_internal(void *arg) -{ - struct lwip_sock *sock; -#ifdef LWIP_DEBUG - int s; -#endif /* LWIP_DEBUG */ - int level, optname; - void *optval; - struct lwip_setgetsockopt_data *data; - - LWIP_ASSERT("arg != NULL", arg != NULL); - - data = (struct lwip_setgetsockopt_data*)arg; - sock = data->sock; -#ifdef LWIP_DEBUG - s = data->s; -#endif /* LWIP_DEBUG */ - level = data->level; - optname = data->optname; - optval = data->optval; - - switch (level) { - -/* Level: SOL_SOCKET */ - case SOL_SOCKET: - switch (optname) { - - /* The option flags */ - case SO_ACCEPTCONN: - case SO_BROADCAST: - /* UNIMPL case SO_DEBUG: */ - /* UNIMPL case SO_DONTROUTE: */ - case SO_KEEPALIVE: - /* UNIMPL case SO_OOBINCLUDE: */ -#if SO_REUSE - case SO_REUSEADDR: - case SO_REUSEPORT: -#endif /* SO_REUSE */ - /*case SO_USELOOPBACK: UNIMPL */ - *(int*)optval = sock->conn->pcb.ip->so_options & optname; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", - s, optname, (*(int*)optval?"on":"off"))); - break; - - case SO_TYPE: - switch (NETCONNTYPE_GROUP(sock->conn->type)) { - case NETCONN_RAW: - *(int*)optval = SOCK_RAW; - break; - case NETCONN_TCP: - *(int*)optval = SOCK_STREAM; - break; - case NETCONN_UDP: - *(int*)optval = SOCK_DGRAM; - break; - default: /* unrecognized socket type */ - *(int*)optval = sock->conn->type; - LWIP_DEBUGF(SOCKETS_DEBUG, - ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", - s, *(int *)optval)); - } /* switch (sock->conn->type) */ - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", - s, *(int *)optval)); - break; - - case SO_ERROR: - /* only overwrite ERR_OK or tempoary errors */ - if ((sock->err == 0) || (sock->err == EINPROGRESS)) { - sock_set_errno(sock, err_to_errno(sock->conn->last_err)); - } - *(int *)optval = sock->err; - sock->err = 0; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", - s, *(int *)optval)); - break; - -#if LWIP_SO_RCVTIMEO - case SO_RCVTIMEO: - *(int *)optval = netconn_get_recvtimeout(sock->conn); - break; -#endif /* LWIP_SO_RCVTIMEO */ -#if LWIP_SO_RCVBUF - case SO_RCVBUF: - *(int *)optval = netconn_get_recvbufsize(sock->conn); - break; -#endif /* LWIP_SO_RCVBUF */ -#if LWIP_UDP - case SO_NO_CHECK: - *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; - break; -#endif /* LWIP_UDP*/ - default: - LWIP_ASSERT("unhandled optname", 0); - break; - } /* switch (optname) */ - break; - -/* Level: IPPROTO_IP */ - case IPPROTO_IP: - switch (optname) { - case IP_TTL: - *(int*)optval = sock->conn->pcb.ip->ttl; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", - s, *(int *)optval)); - break; - case IP_TOS: - *(int*)optval = sock->conn->pcb.ip->tos; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", - s, *(int *)optval)); - break; -#if LWIP_IGMP - case IP_MULTICAST_TTL: - *(u8_t*)optval = sock->conn->pcb.ip->ttl; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", - s, *(int *)optval)); - break; - case IP_MULTICAST_IF: - inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", - s, *(u32_t *)optval)); - break; - case IP_MULTICAST_LOOP: - if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { - *(u8_t*)optval = 1; - } else { - *(u8_t*)optval = 0; - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", - s, *(int *)optval)); - break; -#endif /* LWIP_IGMP */ - default: - LWIP_ASSERT("unhandled optname", 0); - break; - } /* switch (optname) */ - break; - -#if LWIP_TCP -/* Level: IPPROTO_TCP */ - case IPPROTO_TCP: - switch (optname) { - case TCP_NODELAY: - *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", - s, (*(int*)optval)?"on":"off") ); - break; - case TCP_KEEPALIVE: - *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", - s, *(int *)optval)); - break; - -#if LWIP_TCP_KEEPALIVE - case TCP_KEEPIDLE: - *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n", - s, *(int *)optval)); - break; - case TCP_KEEPINTVL: - *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n", - s, *(int *)optval)); - break; - case TCP_KEEPCNT: - *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n", - s, *(int *)optval)); - break; -#endif /* LWIP_TCP_KEEPALIVE */ - default: - LWIP_ASSERT("unhandled optname", 0); - break; - } /* switch (optname) */ - break; -#endif /* LWIP_TCP */ -#if LWIP_UDP && LWIP_UDPLITE - /* Level: IPPROTO_UDPLITE */ - case IPPROTO_UDPLITE: - switch (optname) { - case UDPLITE_SEND_CSCOV: - *(int*)optval = sock->conn->pcb.udp->chksum_len_tx; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", - s, (*(int*)optval)) ); - break; - case UDPLITE_RECV_CSCOV: - *(int*)optval = sock->conn->pcb.udp->chksum_len_rx; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", - s, (*(int*)optval)) ); - break; - default: - LWIP_ASSERT("unhandled optname", 0); - break; - } /* switch (optname) */ - break; -#endif /* LWIP_UDP */ - default: - LWIP_ASSERT("unhandled level", 0); - break; - } /* switch (level) */ - sys_sem_signal(&sock->conn->op_completed); -} - -int -lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) -{ - struct lwip_sock *sock = get_socket(s); - err_t err = ERR_OK; - struct lwip_setgetsockopt_data data; - - if (!sock) { - return -1; - } - - if (NULL == optval) { - sock_set_errno(sock, EFAULT); - return -1; - } - - /* Do length and type checks for the various options first, to keep it readable. */ - switch (level) { - -/* Level: SOL_SOCKET */ - case SOL_SOCKET: - switch (optname) { - - case SO_BROADCAST: - /* UNIMPL case SO_DEBUG: */ - /* UNIMPL case SO_DONTROUTE: */ - case SO_KEEPALIVE: - /* UNIMPL case case SO_CONTIMEO: */ - /* UNIMPL case case SO_SNDTIMEO: */ -#if LWIP_SO_RCVTIMEO - case SO_RCVTIMEO: -#endif /* LWIP_SO_RCVTIMEO */ -#if LWIP_SO_RCVBUF - case SO_RCVBUF: -#endif /* LWIP_SO_RCVBUF */ - /* UNIMPL case SO_OOBINLINE: */ - /* UNIMPL case SO_SNDBUF: */ - /* UNIMPL case SO_RCVLOWAT: */ - /* UNIMPL case SO_SNDLOWAT: */ -#if SO_REUSE - case SO_REUSEADDR: - case SO_REUSEPORT: -#endif /* SO_REUSE */ - /* UNIMPL case SO_USELOOPBACK: */ - if (optlen < sizeof(int)) { - err = EINVAL; - } - break; - case SO_NO_CHECK: - if (optlen < sizeof(int)) { - err = EINVAL; - } -#if LWIP_UDP - if ((sock->conn->type != NETCONN_UDP) || - ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { - /* this flag is only available for UDP, not for UDP lite */ - err = EAFNOSUPPORT; - } -#endif /* LWIP_UDP */ - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - } /* switch (optname) */ - break; - -/* Level: IPPROTO_IP */ - case IPPROTO_IP: - switch (optname) { - /* UNIMPL case IP_HDRINCL: */ - /* UNIMPL case IP_RCVDSTADDR: */ - /* UNIMPL case IP_RCVIF: */ - case IP_TTL: - case IP_TOS: - if (optlen < sizeof(int)) { - err = EINVAL; - } - break; -#if LWIP_IGMP - case IP_MULTICAST_TTL: - if (optlen < sizeof(u8_t)) { - err = EINVAL; - } - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { - err = EAFNOSUPPORT; - } - break; - case IP_MULTICAST_IF: - if (optlen < sizeof(struct in_addr)) { - err = EINVAL; - } - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { - err = EAFNOSUPPORT; - } - break; - case IP_MULTICAST_LOOP: - if (optlen < sizeof(u8_t)) { - err = EINVAL; - } - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { - err = EAFNOSUPPORT; - } - break; - case IP_ADD_MEMBERSHIP: - case IP_DROP_MEMBERSHIP: - if (optlen < sizeof(struct ip_mreq)) { - err = EINVAL; - } - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { - err = EAFNOSUPPORT; - } - break; -#endif /* LWIP_IGMP */ - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - } /* switch (optname) */ - break; - -#if LWIP_TCP -/* Level: IPPROTO_TCP */ - case IPPROTO_TCP: - if (optlen < sizeof(int)) { - err = EINVAL; - break; - } - - /* If this is no TCP socket, ignore any options. */ - if (sock->conn->type != NETCONN_TCP) - return 0; - - switch (optname) { - case TCP_NODELAY: - case TCP_KEEPALIVE: -#if LWIP_TCP_KEEPALIVE - case TCP_KEEPIDLE: - case TCP_KEEPINTVL: - case TCP_KEEPCNT: -#endif /* LWIP_TCP_KEEPALIVE */ - break; - - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - } /* switch (optname) */ - break; -#endif /* LWIP_TCP */ -#if LWIP_UDP && LWIP_UDPLITE -/* Level: IPPROTO_UDPLITE */ - case IPPROTO_UDPLITE: - if (optlen < sizeof(int)) { - err = EINVAL; - break; - } - - /* If this is no UDP lite socket, ignore any options. */ - if (sock->conn->type != NETCONN_UDPLITE) - return 0; - - switch (optname) { - case UDPLITE_SEND_CSCOV: - case UDPLITE_RECV_CSCOV: - break; - - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", - s, optname)); - err = ENOPROTOOPT; - } /* switch (optname) */ - break; -#endif /* LWIP_UDP && LWIP_UDPLITE */ -/* UNDEFINED LEVEL */ - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", - s, level, optname)); - err = ENOPROTOOPT; - } /* switch (level) */ - - - if (err != ERR_OK) { - sock_set_errno(sock, err); - return -1; - } - - - /* Now do the actual option processing */ - data.sock = sock; -#ifdef LWIP_DEBUG - data.s = s; -#endif /* LWIP_DEBUG */ - data.level = level; - data.optname = optname; - data.optval = (void*)optval; - data.optlen = &optlen; - data.err = err; - tcpip_callback(lwip_setsockopt_internal, &data); - sys_arch_sem_wait(&sock->conn->op_completed, 0); - /* maybe lwip_setsockopt_internal has changed err */ - err = data.err; - - sock_set_errno(sock, err); - return err ? -1 : 0; -} - -static void -lwip_setsockopt_internal(void *arg) -{ - struct lwip_sock *sock; -#ifdef LWIP_DEBUG - int s; -#endif /* LWIP_DEBUG */ - int level, optname; - const void *optval; - struct lwip_setgetsockopt_data *data; - - LWIP_ASSERT("arg != NULL", arg != NULL); - - data = (struct lwip_setgetsockopt_data*)arg; - sock = data->sock; -#ifdef LWIP_DEBUG - s = data->s; -#endif /* LWIP_DEBUG */ - level = data->level; - optname = data->optname; - optval = data->optval; - - switch (level) { - -/* Level: SOL_SOCKET */ - case SOL_SOCKET: - switch (optname) { - - /* The option flags */ - case SO_BROADCAST: - /* UNIMPL case SO_DEBUG: */ - /* UNIMPL case SO_DONTROUTE: */ - case SO_KEEPALIVE: - /* UNIMPL case SO_OOBINCLUDE: */ -#if SO_REUSE - case SO_REUSEADDR: - case SO_REUSEPORT: -#endif /* SO_REUSE */ - /* UNIMPL case SO_USELOOPBACK: */ - if (*(int*)optval) { - sock->conn->pcb.ip->so_options |= optname; - } else { - sock->conn->pcb.ip->so_options &= ~optname; - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", - s, optname, (*(int*)optval?"on":"off"))); - break; -#if LWIP_SO_RCVTIMEO - case SO_RCVTIMEO: - netconn_set_recvtimeout(sock->conn, *(int*)optval); - break; -#endif /* LWIP_SO_RCVTIMEO */ -#if LWIP_SO_RCVBUF - case SO_RCVBUF: - netconn_set_recvbufsize(sock->conn, *(int*)optval); - break; -#endif /* LWIP_SO_RCVBUF */ -#if LWIP_UDP - case SO_NO_CHECK: - if (*(int*)optval) { - udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM); - } else { - udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM); - } - break; -#endif /* LWIP_UDP */ - default: - LWIP_ASSERT("unhandled optname", 0); - break; - } /* switch (optname) */ - break; - -/* Level: IPPROTO_IP */ - case IPPROTO_IP: - switch (optname) { - case IP_TTL: - sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", - s, sock->conn->pcb.ip->ttl)); - break; - case IP_TOS: - sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", - s, sock->conn->pcb.ip->tos)); - break; -#if LWIP_IGMP - case IP_MULTICAST_TTL: - sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval); - break; - case IP_MULTICAST_IF: - inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval); - break; - case IP_MULTICAST_LOOP: - if (*(u8_t*)optval) { - udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP); - } else { - udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP); - } - break; - case IP_ADD_MEMBERSHIP: - case IP_DROP_MEMBERSHIP: - { - /* If this is a TCP or a RAW socket, ignore these options. */ - struct ip_mreq *imr = (struct ip_mreq *)optval; - ip_addr_t if_addr; - ip_addr_t multi_addr; - inet_addr_to_ipaddr(&if_addr, &imr->imr_interface); - inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr); - if(optname == IP_ADD_MEMBERSHIP){ - data->err = igmp_joingroup(&if_addr, &multi_addr); - } else { - data->err = igmp_leavegroup(&if_addr, &multi_addr); - } - if(data->err != ERR_OK) { - data->err = EADDRNOTAVAIL; - } - } - break; -#endif /* LWIP_IGMP */ - default: - LWIP_ASSERT("unhandled optname", 0); - break; - } /* switch (optname) */ - break; - -#if LWIP_TCP -/* Level: IPPROTO_TCP */ - case IPPROTO_TCP: - switch (optname) { - case TCP_NODELAY: - if (*(int*)optval) { - tcp_nagle_disable(sock->conn->pcb.tcp); - } else { - tcp_nagle_enable(sock->conn->pcb.tcp); - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", - s, (*(int *)optval)?"on":"off") ); - break; - case TCP_KEEPALIVE: - sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", - s, sock->conn->pcb.tcp->keep_idle)); - break; - -#if LWIP_TCP_KEEPALIVE - case TCP_KEEPIDLE: - sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", - s, sock->conn->pcb.tcp->keep_idle)); - break; - case TCP_KEEPINTVL: - sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", - s, sock->conn->pcb.tcp->keep_intvl)); - break; - case TCP_KEEPCNT: - sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", - s, sock->conn->pcb.tcp->keep_cnt)); - break; -#endif /* LWIP_TCP_KEEPALIVE */ - default: - LWIP_ASSERT("unhandled optname", 0); - break; - } /* switch (optname) */ - break; -#endif /* LWIP_TCP*/ -#if LWIP_UDP && LWIP_UDPLITE - /* Level: IPPROTO_UDPLITE */ - case IPPROTO_UDPLITE: - switch (optname) { - case UDPLITE_SEND_CSCOV: - if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) { - /* don't allow illegal values! */ - sock->conn->pcb.udp->chksum_len_tx = 8; - } else { - sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval; - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", - s, (*(int*)optval)) ); - break; - case UDPLITE_RECV_CSCOV: - if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) { - /* don't allow illegal values! */ - sock->conn->pcb.udp->chksum_len_rx = 8; - } else { - sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval; - } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", - s, (*(int*)optval)) ); - break; - default: - LWIP_ASSERT("unhandled optname", 0); - break; - } /* switch (optname) */ - break; -#endif /* LWIP_UDP */ - default: - LWIP_ASSERT("unhandled level", 0); - break; - } /* switch (level) */ - sys_sem_signal(&sock->conn->op_completed); -} - -int -lwip_ioctl(int s, long cmd, void *argp) -{ - struct lwip_sock *sock = get_socket(s); - u8_t val; -#if LWIP_SO_RCVBUF - u16_t buflen = 0; - s16_t recv_avail; -#endif /* LWIP_SO_RCVBUF */ - - if (!sock) { - return -1; - } - - switch (cmd) { -#if LWIP_SO_RCVBUF - case FIONREAD: - if (!argp) { - sock_set_errno(sock, EINVAL); - return -1; - } - - SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); - if (recv_avail < 0) { - recv_avail = 0; - } - *((u16_t*)argp) = (u16_t)recv_avail; - - /* Check if there is data left from the last recv operation. /maq 041215 */ - if (sock->lastdata) { - struct pbuf *p = (struct pbuf *)sock->lastdata; - if (netconn_type(sock->conn) != NETCONN_TCP) { - p = ((struct netbuf *)p)->p; - } - buflen = p->tot_len; - buflen -= sock->lastoffset; - - *((u16_t*)argp) += buflen; - } - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); - sock_set_errno(sock, 0); - return 0; -#endif /* LWIP_SO_RCVBUF */ - - case FIONBIO: - val = 0; - if (argp && *(u32_t*)argp) { - val = 1; - } - netconn_set_nonblocking(sock->conn, val); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); - sock_set_errno(sock, 0); - return 0; - - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); - sock_set_errno(sock, ENOSYS); /* not yet implemented */ - return -1; - } /* switch (cmd) */ -} - -/** A minimal implementation of fcntl. - * Currently only the commands F_GETFL and F_SETFL are implemented. - * Only the flag O_NONBLOCK is implemented. - */ -int -lwip_fcntl(int s, int cmd, int val) -{ - struct lwip_sock *sock = get_socket(s); - int ret = -1; - - if (!sock || !sock->conn) { - return -1; - } - - switch (cmd) { - case F_GETFL: - ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; - break; - case F_SETFL: - if ((val & ~O_NONBLOCK) == 0) { - /* only O_NONBLOCK, all other bits are zero */ - netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); - ret = 0; - } - break; - default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); - break; - } - return ret; -} - -#endif /* LWIP_SOCKET */ diff --git a/tools/sdk/lwip/src/api/tcpip.c b/tools/sdk/lwip/src/api/tcpip.c deleted file mode 100644 index 01a49d562..000000000 --- a/tools/sdk/lwip/src/api/tcpip.c +++ /dev/null @@ -1,460 +0,0 @@ -/** - * @file - * Sequential API Main thread module - * - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" - -#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/sys.h" -#include "lwip/memp.h" -#include "lwip/mem.h" -#include "lwip/pbuf.h" -#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; -static void *tcpip_init_done_arg; -static sys_mbox_t mbox; - -#if LWIP_TCPIP_CORE_LOCKING -/** The global semaphore to lock the stack. */ -sys_mutex_t lock_tcpip_core; -#endif /* LWIP_TCPIP_CORE_LOCKING */ - - -/** - * The main lwIP thread. This thread has exclusive access to lwIP core functions - * (unless access to them is not locked). Other threads communicate with this - * thread using message boxes. - * - * It also starts all the timers to make sure they are running in the right - * thread context. - * - * @param arg unused argument - */ -static void -tcpip_thread(void *arg) -{ - struct tcpip_msg *msg; - LWIP_UNUSED_ARG(arg); - - if (tcpip_init_done != NULL) {//Óû§×¢²áÁË×Ô¶¨Òå³õʼ»¯º¯Êý - tcpip_init_done(tcpip_init_done_arg); - } - - LOCK_TCPIP_CORE(); - while (1) { /* MAIN Loop */ - UNLOCK_TCPIP_CORE(); - LWIP_TCPIP_THREAD_ALIVE(); - /* wait for a message, timeouts are processed while waiting */ - sys_timeouts_mbox_fetch(&mbox, (void **)&msg); - LOCK_TCPIP_CORE(); - switch (msg->type) { -#if LWIP_NETCONN - case TCPIP_MSG_API://APIµ÷Óà - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); - msg->msg.apimsg->function(&(msg->msg.apimsg->msg)); - break; -#endif /* LWIP_NETCONN */ - -#if !LWIP_TCPIP_CORE_LOCKING_INPUT - case TCPIP_MSG_INPKT://µ×²ãÊý¾Ý°üÊäÈë - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); -#if LWIP_ETHERNET - if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {//Ö§³ÖARP - ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);//½»¸øARP´¦Àí - } else -#endif /* LWIP_ETHERNET */ - { - ip_input(msg->msg.inp.p, msg->msg.inp.netif);//½»¸øIP´¦Àí - } - memp_free(MEMP_TCPIP_MSG_INPKT, msg); - break; -#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ - -#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 */ - - case TCPIP_MSG_CALLBACK://ÉÏ²ã»Øµ÷·½Ê½Ö´ÐÐÒ»¸öº¯Êý - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); - msg->msg.cb.function(msg->msg.cb.ctx); - memp_free(MEMP_TCPIP_MSG_API, msg); - break; - -#if LWIP_TCPIP_TIMEOUT - case TCPIP_MSG_TIMEOUT://Éϲã×¢²áÒ»¸ö¶¨Ê±Ê¼þ - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); - sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); - memp_free(MEMP_TCPIP_MSG_API, msg); - break; - case TCPIP_MSG_UNTIMEOUT://Éϲãɾ³ýÒ»¸ö¶¨Ê±Ê¼þ - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); - sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); - memp_free(MEMP_TCPIP_MSG_API, msg); - break; -#endif /* LWIP_TCPIP_TIMEOUT */ - - default: - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); - LWIP_ASSERT("tcpip_thread: invalid message", 0); - break; - } - } -} - -/** - * Pass a received packet to tcpip_thread for input processing - * - * @param p the received packet, p->payload pointing to the Ethernet header or - * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or - * NETIF_FLAG_ETHERNET flags) - * @param inp the network interface on which the packet was received - */ -err_t -tcpip_input(struct pbuf *p, struct netif *inp) -{ -#if LWIP_TCPIP_CORE_LOCKING_INPUT - err_t ret; - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp)); - LOCK_TCPIP_CORE(); -#if LWIP_ETHERNET - if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { - ret = ethernet_input(p, inp); - } else -#endif /* LWIP_ETHERNET */ - { - ret = ip_input(p, inp); - } - UNLOCK_TCPIP_CORE(); - return ret; -#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ - struct tcpip_msg *msg; - - if (sys_mbox_valid(&mbox)) { - msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); - if (msg == NULL) { - return ERR_MEM; - } - - msg->type = TCPIP_MSG_INPKT; - msg->msg.inp.p = p; - msg->msg.inp.netif = inp; - if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { - memp_free(MEMP_TCPIP_MSG_INPKT, msg); - return ERR_MEM; - } - return ERR_OK; - } - return ERR_VAL; -#endif /* LWIP_TCPIP_CORE_LOCKING_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 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 - */ -err_t -tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block) -{ - struct tcpip_msg *msg; - - if (sys_mbox_valid(&mbox)) { - msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); - if (msg == NULL) { - return ERR_MEM; - } - - msg->type = TCPIP_MSG_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_VAL; -} - -#if LWIP_TCPIP_TIMEOUT -/** - * call sys_timeout in tcpip_thread - * - * @param msec time in milliseconds for timeout - * @param h function to be called on timeout - * @param arg argument to pass to timeout function h - * @return ERR_MEM on memory error, ERR_OK otherwise - */ -err_t -tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) -{ - struct tcpip_msg *msg; - - if (sys_mbox_valid(&mbox)) { - 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; - } - return ERR_VAL; -} - -/** - * call sys_untimeout in tcpip_thread - * - * @param msec time in milliseconds for timeout - * @param h function to be called on timeout - * @param arg argument to pass to timeout function h - * @return ERR_MEM on memory error, ERR_OK otherwise - */ -err_t -tcpip_untimeout(sys_timeout_handler h, void *arg) -{ - struct tcpip_msg *msg; - - if (sys_mbox_valid(&mbox)) { - msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); - if (msg == NULL) { - return ERR_MEM; - } - - msg->type = TCPIP_MSG_UNTIMEOUT; - msg->msg.tmo.h = h; - msg->msg.tmo.arg = arg; - sys_mbox_post(&mbox, msg); - return ERR_OK; - } - return ERR_VAL; -} -#endif /* LWIP_TCPIP_TIMEOUT */ - -#if LWIP_NETCONN -/** - * Call the lower part of a netconn_* function - * This function is then running in the thread context - * of tcpip_thread and has exclusive access to lwIP core code. - * - * @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_apimsg(struct api_msg *apimsg) -{ - struct tcpip_msg msg; -#ifdef LWIP_DEBUG - /* catch functions that don't set err */ - apimsg->msg.err = ERR_VAL; -#endif - - if (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 -/** - * 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_apimsg_lock(struct api_msg *apimsg) -{ -#ifdef LWIP_DEBUG - /* catch functions that don't set err */ - apimsg->msg.err = ERR_VAL; -#endif - - LOCK_TCPIP_CORE(); - apimsg->function(&(apimsg->msg)); - UNLOCK_TCPIP_CORE(); - return apimsg->msg.err; - -} -#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 */ - -/** - * Initialize this module: - * - initialize all sub modules - * - start the tcpip_thread - * - * @param initfunc a function to call when tcpip_thread is running and finished initializing - * @param arg argument to pass to initfunc - */ -void -tcpip_init(tcpip_init_done_fn initfunc, void *arg) -{ - lwip_init();//³õʼ»¯ÄÚºË - - tcpip_init_done = initfunc;//×¢²áÓû§×Ô¶¨Ò庯Êý - tcpip_init_done_arg = arg;//º¯Êý²ÎÊý - 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) { - LWIP_ASSERT("failed to create lock_tcpip_core", 0); - } -#endif /* LWIP_TCPIP_CORE_LOCKING */ - - sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);//´´½¨Äں˽ø³Ì -} - -/** - * Simple callback function used with tcpip_callback to free a pbuf - * (pbuf_free has a wrong signature for tcpip_callback) - * - * @param p The pbuf (chain) to be dereferenced. - */ -static void -pbuf_free_int(void *p) -{ - struct pbuf *q = (struct pbuf *)p; - pbuf_free(q); -} - -/** - * A simple wrapper function that allows you to free a pbuf from interrupt context. - * - * @param p The pbuf (chain) to be dereferenced. - * @return ERR_OK if callback could be enqueued, an err_t if not - */ -err_t -pbuf_free_callback(struct pbuf *p) -{ - return tcpip_callback_with_block(pbuf_free_int, p, 0); -} - -/** - * A simple wrapper function that allows you to free heap memory from - * interrupt context. - * - * @param m the heap memory to free - * @return ERR_OK if callback could be enqueued, an err_t if not - */ -err_t -mem_free_callback(void *m) -{ - return tcpip_callback_with_block(mem_free, m, 0); -} - -#endif /* !NO_SYS */ diff --git a/tools/sdk/lwip/src/app/dhcpserver.c b/tools/sdk/lwip/src/app/dhcpserver.c deleted file mode 100644 index 746392214..000000000 --- a/tools/sdk/lwip/src/app/dhcpserver.c +++ /dev/null @@ -1,1170 +0,0 @@ -#include "lwip/inet.h" -#include "lwip/err.h" -#include "lwip/pbuf.h" -#include "lwip/udp.h" -#include "lwip/mem.h" -#include "osapi.h" -#include "lwip/app/dhcpserver.h" - -#ifndef LWIP_OPEN_SRC -#include "net80211/ieee80211_var.h" -#endif - -#include "user_interface.h" - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -//////////////////////////////////////////////////////////////////////////////////// -//static const uint8_t xid[4] = {0xad, 0xde, 0x12, 0x23}; -//static u8_t old_xid[4] = {0}; -static const uint32 magic_cookie ICACHE_RODATA_ATTR = 0x63538263; -static struct udp_pcb *pcb_dhcps = NULL; -static struct ip_addr broadcast_dhcps; -static struct ip_addr server_address; -static struct ip_addr client_address;//added - -static struct dhcps_lease dhcps_lease; -//static bool dhcps_lease_flag = true; -static list_node *plist = NULL; -static uint8 offer = 0xFF; -static bool renew = false; -#define DHCPS_LEASE_TIME_DEF (120) -uint32 dhcps_lease_time = DHCPS_LEASE_TIME_DEF; //minute - -void wifi_softap_dhcps_client_leave(u8 *bssid, struct ip_addr *ip,bool force); -uint32 wifi_softap_dhcps_client_update(u8 *bssid, struct ip_addr *ip); - -/****************************************************************************** - * FunctionName : node_insert_to_list - * Description : insert the node to the list - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR node_insert_to_list(list_node **phead, list_node* pinsert) -{ - list_node *plist = NULL; - struct dhcps_pool *pdhcps_pool = NULL; - struct dhcps_pool *pdhcps_node = NULL; - if (*phead == NULL) - *phead = pinsert; - else { - plist = *phead; - pdhcps_node = pinsert->pnode; - pdhcps_pool = plist->pnode; - - if(pdhcps_node->ip.addr < pdhcps_pool->ip.addr) { - pinsert->pnext = plist; - *phead = pinsert; - } else { - while (plist->pnext != NULL) { - pdhcps_pool = plist->pnext->pnode; - if (pdhcps_node->ip.addr < pdhcps_pool->ip.addr) { - pinsert->pnext = plist->pnext; - plist->pnext = pinsert; - break; - } - plist = plist->pnext; - } - - if(plist->pnext == NULL) { - plist->pnext = pinsert; - } - } - } -// pinsert->pnext = NULL; -} - -/****************************************************************************** - * FunctionName : node_delete_from_list - * Description : remove the node from list - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR node_remove_from_list(list_node **phead, list_node* pdelete) -{ - list_node *plist = NULL; - - plist = *phead; - if (plist == NULL){ - *phead = NULL; - } else { - if (plist == pdelete){ - *phead = plist->pnext; - pdelete->pnext = NULL; - } else { - while (plist != NULL) { - if (plist->pnext == pdelete){ - plist->pnext = pdelete->pnext; - pdelete->pnext = NULL; - } - plist = plist->pnext; - } - } - } -} - -/////////////////////////////////////////////////////////////////////////////////// -/* - * ��DHCP msg��Ϣ�ṹ���������� - * - * @param optptr -- DHCP msg��Ϣλ�� - * @param type -- Ҫ��ӵ�����option - * - * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ - */ -/////////////////////////////////////////////////////////////////////////////////// -static uint8_t* ICACHE_FLASH_ATTR add_msg_type(uint8_t *optptr, uint8_t type) -{ - - *optptr++ = DHCP_OPTION_MSG_TYPE; - *optptr++ = 1; - *optptr++ = type; - return optptr; -} -/////////////////////////////////////////////////////////////////////////////////// -/* - * ��DHCP msg�ṹ������offerӦ������ - * - * @param optptr -- DHCP msg��Ϣλ�� - * - * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ - */ -/////////////////////////////////////////////////////////////////////////////////// -static uint8_t* ICACHE_FLASH_ATTR add_offer_options(uint8_t *optptr) -{ - struct ip_addr ipadd; - - ipadd.addr = *( (uint32_t *) &server_address); - - struct ip_info if_ip; - os_bzero(&if_ip, sizeof(struct ip_info)); - wifi_get_ip_info(SOFTAP_IF, &if_ip); - - *optptr++ = DHCP_OPTION_SUBNET_MASK; - *optptr++ = 4; - *optptr++ = ip4_addr1( &if_ip.netmask); - *optptr++ = ip4_addr2( &if_ip.netmask); - *optptr++ = ip4_addr3( &if_ip.netmask); - *optptr++ = ip4_addr4( &if_ip.netmask); - - *optptr++ = DHCP_OPTION_LEASE_TIME; - *optptr++ = 4; - *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 24) & 0xFF; - *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 16) & 0xFF; - *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 8) & 0xFF; - *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 0) & 0xFF; - - *optptr++ = DHCP_OPTION_SERVER_ID; - *optptr++ = 4; - *optptr++ = ip4_addr1( &ipadd); - *optptr++ = ip4_addr2( &ipadd); - *optptr++ = ip4_addr3( &ipadd); - *optptr++ = ip4_addr4( &ipadd); - - if (dhcps_router_enabled(offer)){ - *optptr++ = DHCP_OPTION_ROUTER; - *optptr++ = 4; - *optptr++ = ip4_addr1( &if_ip.gw); - *optptr++ = ip4_addr2( &if_ip.gw); - *optptr++ = ip4_addr3( &if_ip.gw); - *optptr++ = ip4_addr4( &if_ip.gw); - } - -#ifdef USE_DNS - *optptr++ = DHCP_OPTION_DNS_SERVER; - *optptr++ = 4; - *optptr++ = ip4_addr1( &ipadd); - *optptr++ = ip4_addr2( &ipadd); - *optptr++ = ip4_addr3( &ipadd); - *optptr++ = ip4_addr4( &ipadd); -#endif - -#ifdef CLASS_B_NET - *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS; - *optptr++ = 4; - *optptr++ = ip4_addr1( &ipadd); - *optptr++ = 255; - *optptr++ = 255; - *optptr++ = 255; -#else - *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS; - *optptr++ = 4; - *optptr++ = ip4_addr1( &ipadd); - *optptr++ = ip4_addr2( &ipadd); - *optptr++ = ip4_addr3( &ipadd); - *optptr++ = 255; -#endif - - *optptr++ = DHCP_OPTION_INTERFACE_MTU; - *optptr++ = 2; -#ifdef CLASS_B_NET - *optptr++ = 0x05; - *optptr++ = 0xdc; -#else - *optptr++ = 0x02; - *optptr++ = 0x40; -#endif - - *optptr++ = DHCP_OPTION_PERFORM_ROUTER_DISCOVERY; - *optptr++ = 1; - *optptr++ = 0x00; - - *optptr++ = 43; - *optptr++ = 6; - - *optptr++ = 0x01; - *optptr++ = 4; - *optptr++ = 0x00; - *optptr++ = 0x00; - *optptr++ = 0x00; - *optptr++ = 0x02; - - return optptr; -} -/////////////////////////////////////////////////////////////////////////////////// -/* - * ��DHCP msg�ṹ����ӽ����־���� - * - * @param optptr -- DHCP msg��Ϣλ�� - * - * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ - */ -/////////////////////////////////////////////////////////////////////////////////// -static uint8_t* ICACHE_FLASH_ATTR add_end(uint8_t *optptr) -{ - - *optptr++ = DHCP_OPTION_END; - return optptr; -} -/////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////// -static void ICACHE_FLASH_ATTR create_msg(struct dhcps_msg *m) -{ - struct ip_addr client; - - client.addr = client_address.addr; - - m->op = DHCP_REPLY; - m->htype = DHCP_HTYPE_ETHERNET; - m->hlen = 6; - m->hops = 0; -// os_memcpy((char *) xid, (char *) m->xid, sizeof(m->xid)); - m->secs = 0; - m->flags = htons(BOOTP_BROADCAST); - - os_memcpy((char *) m->yiaddr, (char *) &client.addr, sizeof(m->yiaddr)); - - os_memset((char *) m->ciaddr, 0, sizeof(m->ciaddr)); - os_memset((char *) m->siaddr, 0, sizeof(m->siaddr)); - os_memset((char *) m->giaddr, 0, sizeof(m->giaddr)); - os_memset((char *) m->sname, 0, sizeof(m->sname)); - os_memset((char *) m->file, 0, sizeof(m->file)); - - os_memset((char *) m->options, 0, sizeof(m->options)); - -//For xiaomi crash bug - uint32 magic_cookie1 = magic_cookie; - os_memcpy((char *) m->options, &magic_cookie1, sizeof(magic_cookie1)); -} -/////////////////////////////////////////////////////////////////////////////////// -/* - * ����һ��OFFER - * - * @param -- m ָ����Ҫ���͵�DHCP msg���� - */ -/////////////////////////////////////////////////////////////////////////////////// -static void ICACHE_FLASH_ATTR send_offer(struct dhcps_msg *m) -{ - uint8_t *end; - struct pbuf *p, *q; - u8_t *data; - u16_t cnt=0; - u16_t i; - err_t SendOffer_err_t; - create_msg(m); - - end = add_msg_type(&m->options[4], DHCPOFFER); - end = add_offer_options(end); - end = add_end(end); - - p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM); -#if DHCPS_DEBUG - os_printf("udhcp: send_offer>>p->ref = %d\n", p->ref); -#endif - if(p != NULL){ - -#if DHCPS_DEBUG - os_printf("dhcps: send_offer>>pbuf_alloc succeed\n"); - os_printf("dhcps: send_offer>>p->tot_len = %d\n", p->tot_len); - os_printf("dhcps: send_offer>>p->len = %d\n", p->len); -#endif - q = p; - while(q != NULL){ - data = (u8_t *)q->payload; - for(i=0; ilen; i++) - { - data[i] = ((u8_t *) m)[cnt++]; - } - - q = q->next; - } - }else{ - -#if DHCPS_DEBUG - os_printf("dhcps: send_offer>>pbuf_alloc failed\n"); -#endif - return; - } - SendOffer_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT ); -#if DHCPS_DEBUG - os_printf("dhcps: send_offer>>udp_sendto result %x\n",SendOffer_err_t); -#endif - if(p->ref != 0){ -#if DHCPS_DEBUG - os_printf("udhcp: send_offer>>free pbuf\n"); -#endif - pbuf_free(p); - } -} -/////////////////////////////////////////////////////////////////////////////////// -/* - * ����һ��NAK��Ϣ - * - * @param m ָ����Ҫ���͵�DHCP msg���� - */ -/////////////////////////////////////////////////////////////////////////////////// -static void ICACHE_FLASH_ATTR send_nak(struct dhcps_msg *m) -{ - - u8_t *end; - struct pbuf *p, *q; - u8_t *data; - u16_t cnt=0; - u16_t i; - err_t SendNak_err_t; - create_msg(m); - - end = add_msg_type(&m->options[4], DHCPNAK); - end = add_end(end); - - p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM); -#if DHCPS_DEBUG - os_printf("udhcp: send_nak>>p->ref = %d\n", p->ref); -#endif - if(p != NULL){ - -#if DHCPS_DEBUG - os_printf("dhcps: send_nak>>pbuf_alloc succeed\n"); - os_printf("dhcps: send_nak>>p->tot_len = %d\n", p->tot_len); - os_printf("dhcps: send_nak>>p->len = %d\n", p->len); -#endif - q = p; - while(q != NULL){ - data = (u8_t *)q->payload; - for(i=0; ilen; i++) - { - data[i] = ((u8_t *) m)[cnt++]; - } - - q = q->next; - } - }else{ - -#if DHCPS_DEBUG - os_printf("dhcps: send_nak>>pbuf_alloc failed\n"); -#endif - return; - } - SendNak_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT ); -#if DHCPS_DEBUG - os_printf("dhcps: send_nak>>udp_sendto result %x\n",SendNak_err_t); -#endif - if(p->ref != 0){ -#if DHCPS_DEBUG - os_printf("udhcp: send_nak>>free pbuf\n"); -#endif - pbuf_free(p); - } -} -/////////////////////////////////////////////////////////////////////////////////// -/* - * ����һ��ACK��DHCP�ͻ��� - * - * @param m ָ����Ҫ���͵�DHCP msg���� - */ -/////////////////////////////////////////////////////////////////////////////////// -static void ICACHE_FLASH_ATTR send_ack(struct dhcps_msg *m) -{ - - u8_t *end; - struct pbuf *p, *q; - u8_t *data; - u16_t cnt=0; - u16_t i; - err_t SendAck_err_t; - create_msg(m); - - end = add_msg_type(&m->options[4], DHCPACK); - end = add_offer_options(end); - end = add_end(end); - - p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM); -#if DHCPS_DEBUG - os_printf("udhcp: send_ack>>p->ref = %d\n", p->ref); -#endif - if(p != NULL){ - -#if DHCPS_DEBUG - os_printf("dhcps: send_ack>>pbuf_alloc succeed\n"); - os_printf("dhcps: send_ack>>p->tot_len = %d\n", p->tot_len); - os_printf("dhcps: send_ack>>p->len = %d\n", p->len); -#endif - q = p; - while(q != NULL){ - data = (u8_t *)q->payload; - for(i=0; ilen; i++) - { - data[i] = ((u8_t *) m)[cnt++]; - } - - q = q->next; - } - }else{ - -#if DHCPS_DEBUG - os_printf("dhcps: send_ack>>pbuf_alloc failed\n"); -#endif - return; - } - SendAck_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT ); -#if DHCPS_DEBUG - os_printf("dhcps: send_ack>>udp_sendto result %x\n",SendAck_err_t); -#endif - - if(p->ref != 0){ -#if DHCPS_DEBUG - os_printf("udhcp: send_ack>>free pbuf\n"); -#endif - pbuf_free(p); - } -} -/////////////////////////////////////////////////////////////////////////////////// -/* - * ����DHCP�ͻ��˷�����DHCP����������Ϣ�����Բ�ͬ��DHCP��������������Ӧ��Ӧ�� - * - * @param optptr DHCP msg��������� - * @param len ��������Ĵ��?(byte) - * - * @return uint8_t ���ش�����DHCP Server״ֵ̬ - */ -/////////////////////////////////////////////////////////////////////////////////// -static uint8_t ICACHE_FLASH_ATTR parse_options(uint8_t *optptr, sint16_t len) -{ - struct ip_addr client; - bool is_dhcp_parse_end = false; - struct dhcps_state s; - - client.addr = *( (uint32_t *) &client_address);// Ҫ�����DHCP�ͻ��˵�IP - - u8_t *end = optptr + len; - u16_t type = 0; - - s.state = DHCPS_STATE_IDLE; - - while (optptr < end) { -#if DHCPS_DEBUG - os_printf("dhcps: (sint16_t)*optptr = %d\n", (sint16_t)*optptr); -#endif - switch ((sint16_t) *optptr) { - - case DHCP_OPTION_MSG_TYPE: //53 - type = *(optptr + 2); - break; - - case DHCP_OPTION_REQ_IPADDR://50 - //os_printf("dhcps:0x%08x,0x%08x\n",client.addr,*(uint32*)(optptr+2)); - if( os_memcmp( (char *) &client.addr, (char *) optptr+2,4)==0 ) { -#if DHCPS_DEBUG - os_printf("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); -#endif - s.state = DHCPS_STATE_ACK; - }else { -#if DHCPS_DEBUG - os_printf("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); -#endif - s.state = DHCPS_STATE_NAK; - } - break; - case DHCP_OPTION_END: - { - is_dhcp_parse_end = true; - } - break; - } - - if(is_dhcp_parse_end){ - break; - } - - optptr += optptr[1] + 2; - } - - switch (type){ - case DHCPDISCOVER://1 - s.state = DHCPS_STATE_OFFER; -#if DHCPS_DEBUG - os_printf("dhcps: DHCPD_STATE_OFFER\n"); -#endif - break; - - case DHCPREQUEST://3 - if ( !(s.state == DHCPS_STATE_ACK || s.state == DHCPS_STATE_NAK) ) { - if(renew == true) { - s.state = DHCPS_STATE_ACK; - } else { - s.state = DHCPS_STATE_NAK; - } -#if DHCPS_DEBUG - os_printf("dhcps: DHCPD_STATE_NAK\n"); -#endif - } - break; - - case DHCPDECLINE://4 - s.state = DHCPS_STATE_IDLE; -#if DHCPS_DEBUG - os_printf("dhcps: DHCPD_STATE_IDLE\n"); -#endif - break; - - case DHCPRELEASE://7 - s.state = DHCPS_STATE_RELEASE; -#if DHCPS_DEBUG - os_printf("dhcps: DHCPD_STATE_IDLE\n"); -#endif - break; - } -#if DHCPS_DEBUG - os_printf("dhcps: return s.state = %d\n", s.state); -#endif - return s.state; -} -/////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////// -static sint16_t ICACHE_FLASH_ATTR parse_msg(struct dhcps_msg *m, u16_t len) -{ - if(os_memcmp((char *)m->options, - &magic_cookie, - sizeof(magic_cookie)) == 0){ - struct ip_addr ip; - os_memcpy(&ip.addr,m->ciaddr,sizeof(ip.addr)); - client_address.addr = wifi_softap_dhcps_client_update(m->chaddr,&ip); - - sint16_t ret = parse_options(&m->options[4], len); - - if(ret == DHCPS_STATE_RELEASE) { - wifi_softap_dhcps_client_leave(m->chaddr,&ip,TRUE); // force to delete - client_address.addr = ip.addr; - } - - return ret; - } - return 0; -} -/////////////////////////////////////////////////////////////////////////////////// -/* - * DHCP ��������ݰ���մ���ص�����˺�����LWIP UDPģ������ʱ������ - * ��Ҫ����udp_recv()������LWIP����ע��. - * - * @param arg - * @param pcb ���յ�UDP��Ŀ��ƿ�? - * @param p ���յ���UDP��������? - * @param addr ���ʹ�UDP���Դ�����IP��ַ - * @param port ���ʹ�UDP���Դ�����UDPͨ���˿ں� - */ -/////////////////////////////////////////////////////////////////////////////////// -static void ICACHE_FLASH_ATTR handle_dhcp(void *arg, - struct udp_pcb *pcb, - struct pbuf *p, - struct ip_addr *addr, - uint16_t port) -{ - struct dhcps_msg *pmsg_dhcps = NULL; - sint16_t tlen = 0; - u16_t i = 0; - u16_t dhcps_msg_cnt = 0; - u8_t *p_dhcps_msg = NULL; - u8_t *data = NULL; - -#if DHCPS_DEBUG - os_printf("dhcps: handle_dhcp-> receive a packet\n"); -#endif - if (p==NULL) return; - - pmsg_dhcps = (struct dhcps_msg *)os_zalloc(sizeof(struct dhcps_msg)); - if (NULL == pmsg_dhcps){ - pbuf_free(p); - return; - } - p_dhcps_msg = (u8_t *)pmsg_dhcps; - tlen = p->tot_len; - data = p->payload; - -#if DHCPS_DEBUG - os_printf("dhcps: handle_dhcp-> p->tot_len = %d\n", tlen); - os_printf("dhcps: handle_dhcp-> p->len = %d\n", p->len); -#endif - - for(i=0; ilen; i++){ - p_dhcps_msg[dhcps_msg_cnt++] = data[i]; - } - - if(p->next != NULL) { -#if DHCPS_DEBUG - os_printf("dhcps: handle_dhcp-> p->next != NULL\n"); - os_printf("dhcps: handle_dhcp-> p->next->tot_len = %d\n",p->next->tot_len); - os_printf("dhcps: handle_dhcp-> p->next->len = %d\n",p->next->len); -#endif - - data = p->next->payload; - for(i=0; inext->len; i++){ - p_dhcps_msg[dhcps_msg_cnt++] = data[i]; - } - } - - /* - * DHCP �ͻ���������Ϣ���� - */ -#if DHCPS_DEBUG - os_printf("dhcps: handle_dhcp-> parse_msg(p)\n"); -#endif - - switch(parse_msg(pmsg_dhcps, tlen - 240)) { - - case DHCPS_STATE_OFFER://1 -#if DHCPS_DEBUG - os_printf("dhcps: handle_dhcp-> DHCPD_STATE_OFFER\n"); -#endif - send_offer(pmsg_dhcps); - break; - case DHCPS_STATE_ACK://3 -#if DHCPS_DEBUG - os_printf("dhcps: handle_dhcp-> DHCPD_STATE_ACK\n"); -#endif - send_ack(pmsg_dhcps); - break; - case DHCPS_STATE_NAK://4 -#if DHCPS_DEBUG - os_printf("dhcps: handle_dhcp-> DHCPD_STATE_NAK\n"); -#endif - send_nak(pmsg_dhcps); - break; - default : - break; - } -#if DHCPS_DEBUG - os_printf("dhcps: handle_dhcp-> pbuf_free(p)\n"); -#endif - pbuf_free(p); - os_free(pmsg_dhcps); - pmsg_dhcps = NULL; -} -/////////////////////////////////////////////////////////////////////////////////// -static void ICACHE_FLASH_ATTR wifi_softap_init_dhcps_lease(uint32 ip) -{ - uint32 softap_ip = 0,local_ip = 0; - uint32 start_ip = 0; - uint32 end_ip = 0; -// if (dhcps_lease_flag) { - if (dhcps_lease.enable == TRUE) { - softap_ip = htonl(ip); - start_ip = htonl(dhcps_lease.start_ip.addr); - end_ip = htonl(dhcps_lease.end_ip.addr); - /*config ip information can't contain local ip*/ - if ((start_ip <= softap_ip) && (softap_ip <= end_ip)) { - dhcps_lease.enable = FALSE; - } else { - /*config ip information must be in the same segment as the local ip*/ - softap_ip >>= 8; - if (((start_ip >> 8 != softap_ip) || (end_ip >> 8 != softap_ip)) - || (end_ip - start_ip > DHCPS_MAX_LEASE)) { - dhcps_lease.enable = FALSE; - } - } - } - - if (dhcps_lease.enable == FALSE) { - local_ip = softap_ip = htonl(ip); - softap_ip &= 0xFFFFFF00; - local_ip &= 0xFF; - if (local_ip >= 0x80) - local_ip -= DHCPS_MAX_LEASE; - else - local_ip ++; - - os_bzero(&dhcps_lease, sizeof(dhcps_lease)); - dhcps_lease.start_ip.addr = softap_ip | local_ip; - dhcps_lease.end_ip.addr = softap_ip | (local_ip + DHCPS_MAX_LEASE - 1); - dhcps_lease.start_ip.addr = htonl(dhcps_lease.start_ip.addr); - dhcps_lease.end_ip.addr= htonl(dhcps_lease.end_ip.addr); - } -// dhcps_lease.start_ip.addr = htonl(dhcps_lease.start_ip.addr); -// dhcps_lease.end_ip.addr= htonl(dhcps_lease.end_ip.addr); -// os_printf("start_ip = 0x%x, end_ip = 0x%x\n",dhcps_lease.start_ip, dhcps_lease.end_ip); -} -/////////////////////////////////////////////////////////////////////////////////// -void ICACHE_FLASH_ATTR dhcps_start(struct ip_info *info) -{ - struct netif * apnetif = (struct netif *)eagle_lwip_getif(0x01); - - if(apnetif->dhcps_pcb != NULL) { - udp_remove(apnetif->dhcps_pcb); - } - - pcb_dhcps = udp_new(); - if (pcb_dhcps == NULL || info ==NULL) { - os_printf("dhcps_start(): could not obtain pcb\n"); - } - - apnetif->dhcps_pcb = pcb_dhcps; - - IP4_ADDR(&broadcast_dhcps, 255, 255, 255, 255); - - server_address = info->ip; - wifi_softap_init_dhcps_lease(server_address.addr); - - udp_bind(pcb_dhcps, IP_ADDR_ANY, DHCPS_SERVER_PORT); - udp_recv(pcb_dhcps, handle_dhcp, NULL); -#if DHCPS_DEBUG - os_printf("dhcps:dhcps_start->udp_recv function Set a receive callback handle_dhcp for UDP_PCB pcb_dhcps\n"); -#endif - -} - -void ICACHE_FLASH_ATTR dhcps_stop(void) -{ - struct netif * apnetif = (struct netif *)eagle_lwip_getif(0x01); - - udp_disconnect(pcb_dhcps); -// dhcps_lease_flag = true; - if(apnetif->dhcps_pcb != NULL) { - udp_remove(apnetif->dhcps_pcb); - apnetif->dhcps_pcb = NULL; - } - - //udp_remove(pcb_dhcps); - list_node *pnode = NULL; - list_node *pback_node = NULL; - struct dhcps_pool* dhcp_node = NULL; - struct ip_addr ip_zero; - - os_memset(&ip_zero,0x0,sizeof(ip_zero)); - pnode = plist; - while (pnode != NULL) { - pback_node = pnode; - pnode = pback_node->pnext; - node_remove_from_list(&plist, pback_node); - dhcp_node = (struct dhcps_pool*)pback_node->pnode; - //wifi_softap_dhcps_client_leave(dhcp_node->mac,&dhcp_node->ip,TRUE); // force to delete - wifi_softap_set_station_info(dhcp_node->mac, &ip_zero); - os_free(pback_node->pnode); - pback_node->pnode = NULL; - os_free(pback_node); - pback_node = NULL; - } -} - -/****************************************************************************** - * FunctionName : wifi_softap_set_dhcps_lease - * Description : set the lease information of DHCP server - * Parameters : please -- Additional argument to set the lease information, - * Little-Endian. - * Returns : true or false -*******************************************************************************/ -bool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_lease(struct dhcps_lease *please) -{ - struct ip_info info; - uint32 softap_ip = 0; - uint32 start_ip = 0; - uint32 end_ip = 0; - - uint8 opmode = wifi_get_opmode(); - - if (opmode == STATION_MODE || opmode == NULL_MODE) { - return false; - } - - if (please == NULL || wifi_softap_dhcps_status() == DHCP_STARTED) - return false; - - if(please->enable) { - os_bzero(&info, sizeof(struct ip_info)); - wifi_get_ip_info(SOFTAP_IF, &info); - softap_ip = htonl(info.ip.addr); - start_ip = htonl(please->start_ip.addr); - end_ip = htonl(please->end_ip.addr); - - /*config ip information can't contain local ip*/ - if ((start_ip <= softap_ip) && (softap_ip <= end_ip)) - return false; - - /*config ip information must be in the same segment as the local ip*/ - softap_ip >>= 8; - if ((start_ip >> 8 != softap_ip) - || (end_ip >> 8 != softap_ip)) { - return false; - } - - if (end_ip - start_ip > DHCPS_MAX_LEASE) - return false; - - os_bzero(&dhcps_lease, sizeof(dhcps_lease)); -// dhcps_lease.start_ip.addr = start_ip; -// dhcps_lease.end_ip.addr = end_ip; - dhcps_lease.start_ip.addr = please->start_ip.addr; - dhcps_lease.end_ip.addr = please->end_ip.addr; - } - dhcps_lease.enable = please->enable; -// dhcps_lease_flag = false; - return true; -} - -/****************************************************************************** - * FunctionName : wifi_softap_get_dhcps_lease - * Description : get the lease information of DHCP server - * Parameters : please -- Additional argument to get the lease information, - * Little-Endian. - * Returns : true or false -*******************************************************************************/ -bool ICACHE_FLASH_ATTR wifi_softap_get_dhcps_lease(struct dhcps_lease *please) -{ - uint8 opmode = wifi_get_opmode(); - - if (opmode == STATION_MODE || opmode == NULL_MODE) { - return false; - } - - if (NULL == please) - return false; - -// if (dhcps_lease_flag){ - if (dhcps_lease.enable == FALSE){ - if (wifi_softap_dhcps_status() == DHCP_STOPPED) - return false; - } else { -// os_bzero(please, sizeof(dhcps_lease)); -// if (wifi_softap_dhcps_status() == DHCP_STOPPED){ -// please->start_ip.addr = htonl(dhcps_lease.start_ip.addr); -// please->end_ip.addr = htonl(dhcps_lease.end_ip.addr); -// } - } - -// if (wifi_softap_dhcps_status() == DHCP_STARTED){ -// os_bzero(please, sizeof(dhcps_lease)); -// please->start_ip.addr = dhcps_lease.start_ip.addr; -// please->end_ip.addr = dhcps_lease.end_ip.addr; -// } - please->start_ip.addr = dhcps_lease.start_ip.addr; - please->end_ip.addr = dhcps_lease.end_ip.addr; - return true; -} - -static void ICACHE_FLASH_ATTR kill_oldest_dhcps_pool(void) -{ - list_node *pre = NULL, *p = NULL; - list_node *minpre = NULL, *minp = NULL; - struct dhcps_pool *pdhcps_pool = NULL, *pmin_pool = NULL; - pre = plist; - p = pre->pnext; - minpre = pre; - minp = p; - while (p != NULL){ - pdhcps_pool = p->pnode; - pmin_pool = minp->pnode; - if (pdhcps_pool->lease_timer < pmin_pool->lease_timer){ - minp = p; - minpre = pre; - } - pre = p; - p = p->pnext; - } - minpre->pnext = minp->pnext;pdhcps_pool->state = DHCPS_STATE_OFFLINE; - os_free(minp->pnode); - minp->pnode = NULL; - os_free(minp); - minp = NULL; -} - -void ICACHE_FLASH_ATTR dhcps_coarse_tmr(void) -{ - uint8 num_dhcps_pool = 0; - list_node *pback_node = NULL; - list_node *pnode = NULL; - struct dhcps_pool *pdhcps_pool = NULL; - pnode = plist; - while (pnode != NULL) { - pdhcps_pool = pnode->pnode; - if ( pdhcps_pool->type == DHCPS_TYPE_DYNAMIC) { - pdhcps_pool->lease_timer --; - } - if (pdhcps_pool->lease_timer == 0){ - pback_node = pnode; - pnode = pback_node->pnext; - node_remove_from_list(&plist,pback_node); - os_free(pback_node->pnode); - pback_node->pnode = NULL; - os_free(pback_node); - pback_node = NULL; - } else { - pnode = pnode ->pnext; - num_dhcps_pool ++; - } - } - - if (num_dhcps_pool >= MAX_STATION_NUM) - kill_oldest_dhcps_pool(); -} - -bool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg) -{ - bool offer_flag = true; - uint8 option = 0; - if (optarg == NULL && wifi_softap_dhcps_status() == false) - return false; - - if (level <= OFFER_START || level >= OFFER_END) - return false; - - switch (level){ - case OFFER_ROUTER: - offer = (*(uint8 *)optarg) & 0x01; - offer_flag = true; - break; - default : - offer_flag = false; - break; - } - return offer_flag; -} - -bool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_lease_time(uint32 minute) -{ - uint8 opmode = wifi_get_opmode(); - - if (opmode == STATION_MODE || opmode == NULL_MODE) { - return false; - } - - if (wifi_softap_dhcps_status() == DHCP_STARTED) { - return false; - } - - if(minute == 0) { - return false; - } - dhcps_lease_time = minute; - return true; -} - -bool ICACHE_FLASH_ATTR wifi_softap_reset_dhcps_lease_time(void) -{ - uint8 opmode = wifi_get_opmode(); - - if (opmode == STATION_MODE || opmode == NULL_MODE) { - return false; - } - - if (wifi_softap_dhcps_status() == DHCP_STARTED) { - return false; - } - dhcps_lease_time = DHCPS_LEASE_TIME_DEF; - return true; -} - -uint32 ICACHE_FLASH_ATTR wifi_softap_get_dhcps_lease_time(void) // minute -{ - return dhcps_lease_time; -} - -void ICACHE_FLASH_ATTR wifi_softap_dhcps_client_leave(u8 *bssid, struct ip_addr *ip,bool force) -{ - struct dhcps_pool *pdhcps_pool = NULL; - list_node *pback_node = NULL; - - if ((bssid == NULL) || (ip == NULL)) { - return; - } - - for (pback_node = plist; pback_node != NULL;pback_node = pback_node->pnext) { - pdhcps_pool = pback_node->pnode; - if (os_memcmp(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)) == 0){ - if (os_memcmp(&pdhcps_pool->ip.addr, &ip->addr, sizeof(pdhcps_pool->ip.addr)) == 0) { - if ((pdhcps_pool->type == DHCPS_TYPE_STATIC) || (force)) { - if(pback_node != NULL) { - node_remove_from_list(&plist,pback_node); - os_free(pback_node); - pback_node = NULL; - } - - if (pdhcps_pool != NULL) { - os_free(pdhcps_pool); - pdhcps_pool = NULL; - } - } else { - pdhcps_pool->state = DHCPS_STATE_OFFLINE; - } - - struct ip_addr ip_zero; - os_memset(&ip_zero,0x0,sizeof(ip_zero)); - wifi_softap_set_station_info(bssid, &ip_zero); - break; - } - } - } -} - -uint32 ICACHE_FLASH_ATTR wifi_softap_dhcps_client_update(u8 *bssid, struct ip_addr *ip) -{ - struct dhcps_pool *pdhcps_pool = NULL; - list_node *pback_node = NULL; - list_node *pmac_node = NULL; - list_node *pip_node = NULL; - bool flag = FALSE; - uint32 start_ip = dhcps_lease.start_ip.addr; - uint32 end_ip = dhcps_lease.end_ip.addr; - dhcps_type_t type = DHCPS_TYPE_DYNAMIC; - if (bssid == NULL) { - return IPADDR_ANY; - } - - if (ip) { - if (IPADDR_BROADCAST == ip->addr) { - return IPADDR_ANY; - } else if (IPADDR_ANY == ip->addr) { - ip = NULL; - } else { - type = DHCPS_TYPE_STATIC; - } - } - - renew = FALSE; - for (pback_node = plist; pback_node != NULL;pback_node = pback_node->pnext) { - pdhcps_pool = pback_node->pnode; - //os_printf("mac:"MACSTR"bssid:"MACSTR"\r\n",MAC2STR(pdhcps_pool->mac),MAC2STR(bssid)); - if (os_memcmp(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)) == 0){ - pmac_node = pback_node; - if (ip == NULL) { - flag = TRUE; - break; - } - } - if (ip != NULL) { - if (os_memcmp(&pdhcps_pool->ip.addr, &ip->addr, sizeof(pdhcps_pool->ip.addr)) == 0) { - pip_node = pback_node; - } - } else if (flag == FALSE){ - if (os_memcmp(&pdhcps_pool->ip.addr, &start_ip, sizeof(pdhcps_pool->ip.addr)) != 0) { - flag = TRUE; - } else { - start_ip = htonl((ntohl(start_ip) + 1)); - } - } - } - - if ((ip == NULL) && (flag == FALSE)) { - if (plist == NULL) { - if (start_ip <= end_ip) { - flag = TRUE; - } else { - return IPADDR_ANY; - } - } else { - if (start_ip > end_ip) { - return IPADDR_ANY; - } - //start_ip = htonl((ntohl(start_ip) + 1)); - flag = TRUE; - } - } - - if (pmac_node != NULL) { // update new ip - if (pip_node != NULL){ - pdhcps_pool = pip_node->pnode; - - if (pip_node != pmac_node) { - if(pdhcps_pool->state != DHCPS_STATE_OFFLINE) { // ip is used - return IPADDR_ANY; - } - - // mac exists and ip exists in other node,delete mac - node_remove_from_list(&plist,pmac_node); - os_free(pmac_node->pnode); - pmac_node->pnode = NULL; - os_free(pmac_node); - pmac_node = pip_node; - os_memcpy(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)); - } else { - renew = true; - type = DHCPS_TYPE_DYNAMIC; - } - - pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; - pdhcps_pool->type = type; - pdhcps_pool->state = DHCPS_STATE_ONLINE; - - } else { - pdhcps_pool = pmac_node->pnode; - if (ip != NULL) { - pdhcps_pool->ip.addr = ip->addr; - } else if (flag == TRUE) { - pdhcps_pool->ip.addr = start_ip; - } else { // no ip to distribute - return IPADDR_ANY; - } - - node_remove_from_list(&plist,pmac_node); - pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; - pdhcps_pool->type = type; - pdhcps_pool->state = DHCPS_STATE_ONLINE; - node_insert_to_list(&plist,pmac_node); - } - } else { // new station - if (pip_node != NULL) { // maybe ip has used - pdhcps_pool = pip_node->pnode; - if (pdhcps_pool->state != DHCPS_STATE_OFFLINE) { - return IPADDR_ANY; - } - os_memcpy(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)); - pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; - pdhcps_pool->type = type; - pdhcps_pool->state = DHCPS_STATE_ONLINE; - } else { - pdhcps_pool = (struct dhcps_pool *)os_zalloc(sizeof(struct dhcps_pool)); - if (ip != NULL) { - pdhcps_pool->ip.addr = ip->addr; - } else if (flag == TRUE) { - pdhcps_pool->ip.addr = start_ip; - } else { // no ip to distribute - os_free(pdhcps_pool); - return IPADDR_ANY; - } - if (pdhcps_pool->ip.addr > end_ip) { - os_free(pdhcps_pool); - return IPADDR_ANY; - } - os_memcpy(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)); - pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; - pdhcps_pool->type = type; - pdhcps_pool->state = DHCPS_STATE_ONLINE; - pback_node = (list_node *)os_zalloc(sizeof(list_node )); - pback_node->pnode = pdhcps_pool; - pback_node->pnext = NULL; - node_insert_to_list(&plist,pback_node); - } - } - wifi_softap_set_station_info(bssid, &pdhcps_pool->ip); - - return pdhcps_pool->ip.addr; -} diff --git a/tools/sdk/lwip/src/app/espconn.c b/tools/sdk/lwip/src/app/espconn.c deleted file mode 100644 index 93ce6fa4c..000000000 --- a/tools/sdk/lwip/src/app/espconn.c +++ /dev/null @@ -1,1347 +0,0 @@ -/****************************************************************************** - * Copyright 2013-2014 Espressif Systems (Wuxi) - * - * FileName: espconn.c - * - * Description: espconn interface for user - * - * Modification history: - * 2014/3/31, v1.0 create this file. -*******************************************************************************/ - -#include "lwip/netif.h" -#include "lwip/inet.h" -#include "netif/etharp.h" -#include "lwip/tcp.h" -#include "lwip/ip.h" -#include "lwip/init.h" -#include "ets_sys.h" -#include "os_type.h" -//#include "os.h" -#include "lwip/mem.h" - -#include "lwip/app/espconn_tcp.h" -#include "lwip/app/espconn_udp.h" -#include "lwip/app/espconn.h" -#include "user_interface.h" - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -espconn_msg *plink_active = NULL; -espconn_msg *pserver_list = NULL; -remot_info premot[linkMax]; - -struct espconn_packet pktinfo[2]; - -void espconn_init(void); - -static uint8 espconn_tcp_get_buf_count(espconn_buf *pesp_buf); -/****************************************************************************** - * FunctionName : espconn_copy_partial - * Description : reconnect with host - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR -espconn_copy_partial(struct espconn *pesp_dest, struct espconn *pesp_source) -{ - pesp_dest->type = pesp_source->type; - pesp_dest->state = pesp_source->state; - if (pesp_source->type == ESPCONN_TCP){ - pesp_dest->proto.tcp->remote_port = pesp_source->proto.tcp->remote_port; - pesp_dest->proto.tcp->local_port = pesp_source->proto.tcp->local_port; - os_memcpy(pesp_dest->proto.tcp->remote_ip, pesp_source->proto.tcp->remote_ip, 4); - os_memcpy(pesp_dest->proto.tcp->local_ip, pesp_source->proto.tcp->local_ip, 4); - pesp_dest->proto.tcp->connect_callback = pesp_source->proto.tcp->connect_callback; - pesp_dest->proto.tcp->reconnect_callback = pesp_source->proto.tcp->reconnect_callback; - pesp_dest->proto.tcp->disconnect_callback = pesp_source->proto.tcp->disconnect_callback; - } else { - pesp_dest->proto.udp->remote_port = pesp_source->proto.udp->remote_port; - pesp_dest->proto.udp->local_port = pesp_source->proto.udp->local_port; - os_memcpy(pesp_dest->proto.udp->remote_ip, pesp_source->proto.udp->remote_ip, 4); - os_memcpy(pesp_dest->proto.udp->local_ip, pesp_source->proto.udp->local_ip, 4); - } - pesp_dest->recv_callback = pesp_source->recv_callback; - pesp_dest->sent_callback = pesp_source->sent_callback; - pesp_dest->link_cnt = pesp_source->link_cnt; - pesp_dest->reverse = pesp_source->reverse; -} - -/****************************************************************************** - * FunctionName : espconn_copy_partial - * Description : insert the node to the active connection list - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR espconn_list_creat(espconn_msg **phead, espconn_msg* pinsert) -{ - espconn_msg *plist = NULL; -// espconn_msg *ptest = NULL; - if (*phead == NULL) - *phead = pinsert; - else { - plist = *phead; - while (plist->pnext != NULL) { - plist = plist->pnext; - } - plist->pnext = pinsert; - } - pinsert->pnext = NULL; - -/* ptest = *phead; - while(ptest != NULL){ - os_printf("espconn_list_creat %p\n", ptest); - ptest = ptest->pnext; - }*/ -} - -/****************************************************************************** - * FunctionName : espconn_list_delete - * Description : remove the node from the active connection list - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR espconn_list_delete(espconn_msg **phead, espconn_msg* pdelete) -{ - espconn_msg *plist = NULL; -// espconn_msg *ptest = NULL; - plist = *phead; - if (plist == NULL){ - *phead = NULL; - } else { - if (plist == pdelete){ - *phead = plist->pnext; - } else { - while (plist != NULL) { - if (plist->pnext == pdelete){ - plist->pnext = pdelete->pnext; - } - plist = plist->pnext; - } - } - } -/* ptest = *phead; - while(ptest != NULL){ - os_printf("espconn_list_delete %p\n", ptest); - ptest = ptest->pnext; - }*/ -} - -/****************************************************************************** - * FunctionName : espconn_pbuf_create - * Description : insert the node to the active connection list - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR espconn_pbuf_create(espconn_buf **phead, espconn_buf* pinsert) -{ - espconn_buf *plist = NULL; - - if (*phead == NULL) - *phead = pinsert; - else { - plist = *phead; - while (plist->pnext != NULL) { - plist = plist->pnext; - } - plist->pnext = pinsert; - } - pinsert->pnext = NULL; -} - -/****************************************************************************** - * FunctionName : espconn_pbuf_delete - * Description : remove the node from the active connection list - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR espconn_pbuf_delete(espconn_buf **phead, espconn_buf* pdelete) -{ - espconn_buf *plist = NULL; - - plist = *phead; - if (plist == NULL){ - *phead = NULL; - } else { - if (plist == pdelete){ - *phead = plist->pnext; - } else { - while (plist != NULL) { - if (plist->pnext == pdelete){ - plist->pnext = pdelete->pnext; - } - plist = plist->pnext; - } - } - } -} - -/****************************************************************************** - * FunctionName : espconn_find_connection - * Description : Initialize the server: set up a listening PCB and bind it to - * the defined port - * Parameters : espconn -- the espconn used to build server - * Returns : true or false - *******************************************************************************/ -bool ICACHE_FLASH_ATTR espconn_find_connection(struct espconn *pespconn, espconn_msg **pnode) -{ - espconn_msg *plist = NULL; - struct ip_addr ip_remot; - struct ip_addr ip_list; - - if (pespconn == NULL) - return false; - - /*find the active connection node*/ - for (plist = plink_active; plist != NULL; plist = plist->pnext){ - if (pespconn == plist->pespconn) { - *pnode = plist; - return true; - } - } - - /*find the active server node*/ - for (plist = pserver_list; plist != NULL; plist = plist->pnext){ - if (pespconn == plist->pespconn) { - if (pespconn->proto.tcp == NULL) - return false; - - IP4_ADDR(&ip_remot, pespconn->proto.tcp->remote_ip[0], - pespconn->proto.tcp->remote_ip[1], - pespconn->proto.tcp->remote_ip[2], - pespconn->proto.tcp->remote_ip[3]); - if ((ip_remot.addr == IPADDR_ANY) || (pespconn->proto.tcp->remote_port == 0)) - return false; - - /*find the active connection node*/ - for (plist = plink_active; plist != NULL; plist = plist->pnext){ - IP4_ADDR(&ip_list, plist->pcommon.remote_ip[0], - plist->pcommon.remote_ip[1], plist->pcommon.remote_ip[2], - plist->pcommon.remote_ip[3]); - if ((ip_list.addr == ip_remot.addr) && (pespconn->proto.tcp->remote_port == plist->pcommon.remote_port)) { - *pnode = plist; - return true; - } - } - return false; - } - } - return false; -} - -/****************************************************************************** - * FunctionName : espconn_get_acticve_num - * Description : get the count of simulatenously active connections - * Parameters : type -- the type - * Returns : the count of simulatenously active connections - *******************************************************************************/ -static uint8 ICACHE_FLASH_ATTR -espconn_get_acticve_num(uint8 type) -{ - espconn_msg *plist = NULL; - uint8 num_tcp_active = 0; - - for (plist = plink_active; plist != NULL; plist = plist->pnext) { - if (plist->pespconn != NULL && plist->pespconn->type == type) { - num_tcp_active++; - } - } - - return num_tcp_active; -} - -/****************************************************************************** - * FunctionName : espconn_connect - * Description : The function given as the connect - * Parameters : espconn -- the espconn used to listen the connection - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_connect(struct espconn *espconn) -{ - struct ip_addr ipaddr; - struct ip_info ipinfo; - uint8 connect_status = 0; - sint8 value = ESPCONN_OK; - espconn_msg *plist = NULL; - remot_info *pinfo = NULL; - - volatile int tmp = (int) espconn_init; - - if (espconn == NULL) { - return ESPCONN_ARG; - } else if (espconn ->type != ESPCONN_TCP) - return ESPCONN_ARG; - - /*Check the active node count whether is the limit or not*/ - if (espconn_get_acticve_num(ESPCONN_TCP) >= espconn_tcp_get_max_con()) - return ESPCONN_ISCONN; - - /*Check the IP address whether is zero or not in different mode*/ - if (wifi_get_opmode() == ESPCONN_STA){ - wifi_get_ip_info(STA_NETIF,&ipinfo); - if (ipinfo.ip.addr == 0){ - return ESPCONN_RTE; - } - } else if(wifi_get_opmode() == ESPCONN_AP){ - wifi_get_ip_info(AP_NETIF,&ipinfo); - if (ipinfo.ip.addr == 0){ - return ESPCONN_RTE; - } - } else if(wifi_get_opmode() == ESPCONN_AP_STA){ - IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0], - espconn->proto.tcp->remote_ip[1], - espconn->proto.tcp->remote_ip[2], - espconn->proto.tcp->remote_ip[3]); - ipaddr.addr <<= 8; - wifi_get_ip_info(AP_NETIF,&ipinfo); - ipinfo.ip.addr <<= 8; - espconn_printf("softap_addr = %x, remote_addr = %x\n", ipinfo.ip.addr, ipaddr.addr); - - if (ipaddr.addr != ipinfo.ip.addr){ - connect_status = wifi_station_get_connect_status(); - if (connect_status == STATION_GOT_IP){ - wifi_get_ip_info(STA_NETIF,&ipinfo); - if (ipinfo.ip.addr == 0) - return ESPCONN_RTE; - } else if (connect_status == STATION_IDLE){ - return ESPCONN_RTE; - } else { - return connect_status; - } - } - } - - /*check the active node information whether is the same as the entity or not*/ - for (plist = plink_active; plist != NULL; plist = plist->pnext){ - if (plist->pespconn && plist->pespconn->type == ESPCONN_TCP){ - if (espconn->proto.tcp->local_port == plist->pespconn->proto.tcp->local_port){ - return ESPCONN_ISCONN; - } - } - } - - value = espconn_tcp_client(espconn); - - return value; -} - -/****************************************************************************** - * FunctionName : espconn_create - * Description : sent data for client or server - * Parameters : espconn -- espconn to the data transmission - * Returns : result -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_create(struct espconn *espconn) -{ - sint8 value = ESPCONN_OK; - espconn_msg *plist = NULL; - - volatile int tmp = (int) espconn_init; - - if (espconn == NULL) { - return ESPCONN_ARG; - } else if (espconn ->type != ESPCONN_UDP){ - return ESPCONN_ARG; - } - - /*check the active node information whether is the same as the entity or not*/ - for (plist = plink_active; plist != NULL; plist = plist->pnext){ - if (plist->pespconn && plist->pespconn->type == ESPCONN_UDP){ - if (espconn->proto.udp->local_port == plist->pespconn->proto.udp->local_port){ - return ESPCONN_ISCONN; - } - } - } - - value = espconn_udp_server(espconn); - - return value; -} - -/****************************************************************************** - * FunctionName : espconn_sent - * Description : sent data for client or server - * Parameters : espconn -- espconn to set for client or server - * psent -- data to send - * length -- length of data to send - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length) -{ - espconn_msg *pnode = NULL; - bool value = false; - err_t error = ESPCONN_OK; - - if (espconn == NULL || psent == NULL || length == 0) { - return ESPCONN_ARG; - } - - /*Find the node depend on the espconn message*/ - value = espconn_find_connection(espconn, &pnode); - - if (value){ - espconn ->state = ESPCONN_WRITE; - switch (espconn ->type) { - case ESPCONN_TCP: - /* calling sent function frequently,make sure last packet has been backup or sent fully*/ - if (pnode->pcommon.write_flag){ - espconn_buf *pbuf = NULL; - /*If total number of espconn_buf on the unsent lists exceeds the set maximum, return an error */ - if (espconn_copy_enabled(pnode)){ - if (espconn_tcp_get_buf_count(pnode->pcommon.pbuf) >= pnode ->pcommon.pbuf_num) - return ESPCONN_MAXNUM; - } else { - struct tcp_pcb *pcb = pnode->pcommon.pcb; - if (pcb->snd_queuelen >= TCP_SND_QUEUELEN) - return ESPCONN_MAXNUM; - } - - pbuf = (espconn_buf*) os_zalloc(sizeof(espconn_buf)); - if (pbuf == NULL) - return ESPCONN_MEM; - else { - /*Backup the application packet information for send more data*/ - pbuf->payload = psent; - pbuf->punsent = pbuf->payload; - pbuf->unsent = length; - pbuf->len = length; - /*insert the espconn_pbuf to the list*/ - espconn_pbuf_create(&pnode->pcommon.pbuf, pbuf); - if (pnode->pcommon.ptail == NULL) - pnode->pcommon.ptail = pbuf; - } - /*when set the data copy option. change the flag for next packet*/ - if (espconn_copy_disabled(pnode)) - pnode->pcommon.write_flag = false; - error = espconn_tcp_write(pnode); -// if (error != ESPCONN_OK){ -// /*send the application packet fail, -// * ensure that each allocated is deleted*/ -// espconn_pbuf_delete(&pnode->pcommon.pbuf, pbuf); -// os_free(pbuf); -// pbuf = NULL; -// } - return error; - } else - return ESPCONN_ARG; - break; - - case ESPCONN_UDP: - return espconn_udp_sent(pnode, psent, length); - break; - - default : - break; - } - } - return ESPCONN_ARG; -} - -sint16 ICACHE_FLASH_ATTR espconn_recv(struct espconn *espconn, void *mem, size_t len) -{ - espconn_msg *pnode = NULL; - bool value = false; - int bytes_used = 0; - if (espconn == NULL || mem == NULL || len == 0) - return ESPCONN_ARG; - - /*Find the node depend on the espconn message*/ - value = espconn_find_connection(espconn, &pnode); - if (value && espconn->type == ESPCONN_TCP){ - if (pnode->readbuf != NULL){ - bytes_used = ringbuf_bytes_used(pnode->readbuf); - if (bytes_used != 0) { - if (len > bytes_used) { - len = bytes_used; - } - ringbuf_memcpy_from(mem, pnode->readbuf, len); - espconn_recv_unhold(pnode->pespconn); - return len; - } else { - return ESPCONN_OK; - } - } else{ - return ESPCONN_OK; - } - } else{ - return ESPCONN_ARG; - } - - return ESPCONN_ARG; -} - -/****************************************************************************** - * FunctionName : espconn_sendto - * Description : send data for UDP - * Parameters : espconn -- espconn to set for UDP - * psent -- data to send - * length -- length of data to send - * Returns : error -*******************************************************************************/ -sint16 ICACHE_FLASH_ATTR -espconn_sendto(struct espconn *espconn, uint8 *psent, uint16 length) -{ - espconn_msg *pnode = NULL; - bool value = false; - err_t error = ESPCONN_OK; - - if (espconn == NULL || psent == NULL || length == 0) { - return ESPCONN_ARG; - } - - /*Find the node depend on the espconn message*/ - value = espconn_find_connection(espconn, &pnode); - if (value && espconn->type == ESPCONN_UDP) - return espconn_udp_sendto(pnode, psent, length); - else - return ESPCONN_ARG; -} - -/****************************************************************************** - * FunctionName : espconn_send - * Description : sent data for client or server - * Parameters : espconn -- espconn to set for client or server - * psent -- data to send - * length -- length of data to send - * Returns : none -*******************************************************************************/ - -sint8 espconn_send(struct espconn *espconn, uint8 *psent, uint16 length) __attribute__((alias("espconn_sent"))); - -/****************************************************************************** - * FunctionName : espconn_tcp_get_wnd - * Description : get the window size of simulatenously active TCP connections - * Parameters : none - * Returns : the number of TCP_MSS active TCP connections -*******************************************************************************/ -uint8 ICACHE_FLASH_ATTR espconn_tcp_get_wnd(void) -{ - uint8 tcp_num = 0; - - tcp_num = (TCP_WND / TCP_MSS); - - return tcp_num; -} -/****************************************************************************** - * FunctionName : espconn_tcp_set_max_con - * Description : set the window size simulatenously active TCP connections - * Parameters : num -- the number of TCP_MSS - * Returns : ESPCONN_ARG -- Illegal argument - * ESPCONN_OK -- No error -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR espconn_tcp_set_wnd(uint8 num) -{ - if (num == 0 || num > linkMax) - return ESPCONN_ARG; - - TCP_WND = (num * TCP_MSS); - return ESPCONN_OK; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_get_mss - * Description : get the mss size of simulatenously active TCP connections - * Parameters : none - * Returns : the size of TCP_MSS active TCP connections -*******************************************************************************/ -uint16 ICACHE_FLASH_ATTR espconn_tcp_get_mss(void) -{ - uint16 tcp_num = 0; - - tcp_num = TCP_MSS; - - return tcp_num; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_get_max_con - * Description : get the number of simulatenously active TCP connections - * Parameters : espconn -- espconn to set the connect callback - * Returns : none -*******************************************************************************/ -uint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_con(void) -{ - uint8 tcp_num = 0; - - tcp_num = MEMP_NUM_TCP_PCB; - - return tcp_num; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_set_max_con - * Description : set the number of simulatenously active TCP connections - * Parameters : espconn -- espconn to set the connect callback - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_con(uint8 num) -{ - if (num == 0 || num > linkMax) - return ESPCONN_ARG; - - MEMP_NUM_TCP_PCB = num; - return ESPCONN_OK; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_get_max_retran - * Description : get the Maximum number of retransmissions of data active TCP connections - * Parameters : none - * Returns : the Maximum number of retransmissions -*******************************************************************************/ -uint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_retran(void) -{ - uint8 tcp_num = 0; - - tcp_num = TCP_MAXRTX; - - return tcp_num; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_set_max_retran - * Description : set the Maximum number of retransmissions of data active TCP connections - * Parameters : num -- the Maximum number of retransmissions - * Returns : result -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_retran(uint8 num) -{ - if (num == 0 || num > 12) - return ESPCONN_ARG; - - TCP_MAXRTX = num; - return ESPCONN_OK; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_get_max_syn - * Description : get the Maximum number of retransmissions of SYN segments - * Parameters : none - * Returns : the Maximum number of retransmissions -*******************************************************************************/ -uint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_syn(void) -{ - uint8 tcp_num = 0; - - tcp_num = TCP_SYNMAXRTX; - - return tcp_num; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_set_max_syn - * Description : set the Maximum number of retransmissions of SYN segments - * Parameters : num -- the Maximum number of retransmissions - * Returns : result -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_syn(uint8 num) -{ - if (num == 0 || num > 12) - return ESPCONN_ARG; - - TCP_SYNMAXRTX = num; - return ESPCONN_OK; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_get_max_con_allow - * Description : get the count of simulatenously active connections on the server - * Parameters : espconn -- espconn to get the count - * Returns : result -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_con_allow(struct espconn *espconn) -{ - espconn_msg *pget_msg = NULL; - if ((espconn == NULL) || (espconn->type == ESPCONN_UDP)) - return ESPCONN_ARG; - - pget_msg = pserver_list; - while (pget_msg != NULL){ - if (pget_msg->pespconn == espconn){ - return pget_msg->count_opt; - } - pget_msg = pget_msg->pnext; - } - return ESPCONN_ARG; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_set_max_con_allow - * Description : set the count of simulatenously active connections on the server - * Parameters : espconn -- espconn to set the count - * Returns : result -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num) -{ - espconn_msg *pset_msg = NULL; - if ((espconn == NULL) || (num > MEMP_NUM_TCP_PCB) || (espconn->type == ESPCONN_UDP)) - return ESPCONN_ARG; - - pset_msg = pserver_list; - while (pset_msg != NULL){ - if (pset_msg->pespconn == espconn){ - pset_msg->count_opt = num; - return ESPCONN_OK; - } - pset_msg = pset_msg->pnext; - } - return ESPCONN_ARG; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_set_buf_count - * Description : set the total number of espconn_buf on the unsent lists for one - * activate connection - * Parameters : espconn -- espconn to set the count - * num -- the total number of espconn_buf - * Returns : result -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR espconn_tcp_set_buf_count(struct espconn *espconn, uint8 num) -{ - espconn_msg *plist = NULL; - if (espconn == NULL || (num > TCP_SND_QUEUELEN)) - return ESPCONN_ARG; - - /*find the node from the active connection list*/ - for (plist = plink_active; plist != NULL; plist = plist->pnext){ - if (plist->pespconn && plist->pespconn == espconn && espconn->type == ESPCONN_TCP){ - plist->pcommon.pbuf_num = num; - return ESPCONN_OK; - } - } - - if (plist == NULL) - return ESPCONN_ARG; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_get_buf_count - * Description : get the count of the current node which has espconn_buf - * Parameters : pesp_buf -- the list head of espconn_buf type - * Returns : the count of the current node which has espconn_buf -*******************************************************************************/ -static uint8 ICACHE_FLASH_ATTR espconn_tcp_get_buf_count(espconn_buf *pesp_buf) -{ - espconn_buf *pbuf_list = pesp_buf; - uint8 pbuf_num = 0; - - /*polling the list get the count of the current node*/ - while (pbuf_list != NULL){ - pbuf_list = pbuf_list->pnext; - pbuf_num ++; - } - return pbuf_num; -} - -/****************************************************************************** - * FunctionName : espconn_regist_sentcb - * Description : Used to specify the function that should be called when data - * has been successfully delivered to the remote host. - * Parameters : espconn -- espconn to set the sent callback - * sent_cb -- sent callback function to call for this espconn - * when data is successfully sent - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb) -{ - if (espconn == NULL) { - return ESPCONN_ARG; - } - - espconn ->sent_callback = sent_cb; - return ESPCONN_OK; -} - -/****************************************************************************** - * FunctionName : espconn_regist_sentcb - * Description : Used to specify the function that should be called when data - * has been successfully delivered to the remote host. - * Parameters : espconn -- espconn to set the sent callback - * sent_cb -- sent callback function to call for this espconn - * when data is successfully sent - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn) -{ - if (espconn == NULL || espconn ->proto.tcp == NULL || espconn->type == ESPCONN_UDP) { - return ESPCONN_ARG; - } - - espconn ->proto.tcp->write_finish_fn = write_finish_fn; - return ESPCONN_OK; -} - -/****************************************************************************** - * FunctionName : espconn_regist_connectcb - * Description : used to specify the function that should be called when - * connects to host. - * Parameters : espconn -- espconn to set the connect callback - * connect_cb -- connected callback function to call when connected - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb) -{ - if (espconn == NULL) { - return ESPCONN_ARG; - } - - espconn->proto.tcp->connect_callback = connect_cb; - return ESPCONN_OK; -} - -/****************************************************************************** - * FunctionName : espconn_regist_recvcb - * Description : used to specify the function that should be called when recv - * data from host. - * Parameters : espconn -- espconn to set the recv callback - * recv_cb -- recv callback function to call when recv data - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb) -{ - if (espconn == NULL) { - return ESPCONN_ARG; - } - - espconn ->recv_callback = recv_cb; - return ESPCONN_OK; -} - -/****************************************************************************** - * FunctionName : espconn_regist_reconcb - * Description : used to specify the function that should be called when connection - * because of err disconnect. - * Parameters : espconn -- espconn to set the err callback - * recon_cb -- err callback function to call when err - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb) -{ - if (espconn == NULL) { - return ESPCONN_ARG; - } - - espconn ->proto.tcp->reconnect_callback = recon_cb; - return ESPCONN_OK; -} - -/****************************************************************************** - * FunctionName : espconn_regist_disconcb - * Description : used to specify the function that should be called when disconnect - * Parameters : espconn -- espconn to set the err callback - * discon_cb -- err callback function to call when err - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb) -{ - if (espconn == NULL) { - return ESPCONN_ARG; - } - - espconn ->proto.tcp->disconnect_callback = discon_cb; - return ESPCONN_OK; -} - -/****************************************************************************** - * FunctionName : espconn_get_connection_info - * Description : used to specify the function that should be called when disconnect - * Parameters : espconn -- espconn to set the err callback - * discon_cb -- err callback function to call when err - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags) -{ - espconn_msg *plist = NULL; - - if (pespconn == NULL) - return ESPCONN_ARG; - - os_memset(premot, 0, sizeof(premot)); - pespconn->link_cnt = 0; - plist = plink_active; - switch (pespconn->type){ - case ESPCONN_TCP: - while(plist != NULL){ - if (plist->preverse == pespconn){ - premot[pespconn->link_cnt].state = plist->pespconn->state; - premot[pespconn->link_cnt].remote_port = plist->pcommon.remote_port; - os_memcpy(premot[pespconn->link_cnt].remote_ip, plist->pcommon.remote_ip, 4); - pespconn->link_cnt ++; - } - plist = plist->pnext; - } - - break; - case ESPCONN_UDP: - while(plist != NULL){ - if (plist->pespconn == pespconn){ - premot[pespconn->link_cnt].state = plist->pespconn->state; - premot[pespconn->link_cnt].remote_port = plist->pcommon.remote_port; - os_memcpy(premot[pespconn->link_cnt].remote_ip, plist->pcommon.remote_ip, 4); - pespconn->link_cnt ++; - } - plist = plist->pnext; - } - break; - default: - break; - } - *pcon_info = premot; - if (pespconn->link_cnt == 0) - return ESPCONN_ARG; - return ESPCONN_OK; -} - -/****************************************************************************** - * FunctionName : espconn_accept - * Description : The function given as the listen - * Parameters : espconn -- the espconn used to listen the connection - * Returns : -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_accept(struct espconn *espconn) -{ - sint8 value = ESPCONN_OK; - espconn_msg *plist = NULL; - - volatile int tmp = (int) espconn_init; - - if (espconn == NULL) { - return ESPCONN_ARG; - } else if (espconn ->type != ESPCONN_TCP) - return ESPCONN_ARG; - - /*check the active node information whether is the same as the entity or not*/ - for (plist = plink_active; plist != NULL; plist = plist->pnext){ - if (plist->pespconn && plist->pespconn->type == ESPCONN_TCP){ - if (espconn->proto.tcp->local_port == plist->pespconn->proto.tcp->local_port){ - return ESPCONN_ISCONN; - } - } - } - value = espconn_tcp_server(espconn); - - return value; -} - -/****************************************************************************** - * FunctionName : espconn_regist_time - * Description : used to specify the time that should be called when don't recv data - * Parameters : espconn -- the espconn used to the connection - * interval -- the timer when don't recv data - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag) -{ - espconn_msg *pnode = NULL; - espconn_msg *ptime_msg = NULL; - bool value = false; - if ((espconn == NULL) || (type_flag > 0x01)) - return ESPCONN_ARG; - - if (type_flag == 0x01){ - /*set the timeout time for one active connection of the server*/ - value = espconn_find_connection(espconn, &pnode); - if (value){ - pnode->pcommon.timeout = interval; - return ESPCONN_OK; - } else - return ESPCONN_ARG; - } else { - /*set the timeout time for all active connection of the server*/ - ptime_msg = pserver_list; - while (ptime_msg != NULL){ - if (ptime_msg->pespconn == espconn){ - ptime_msg->pcommon.timeout = interval; - return ESPCONN_OK; - } - ptime_msg = ptime_msg->pnext; - } - } - return ESPCONN_ARG; -} - -/****************************************************************************** - * FunctionName : espconn_disconnect - * Description : disconnect with host - * Parameters : espconn -- the espconn used to disconnect the connection - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_disconnect(struct espconn *espconn) -{ - espconn_msg *pnode = NULL; - bool value = false; - - if (espconn == NULL) { - return ESPCONN_ARG;; - } else if (espconn ->type != ESPCONN_TCP) - return ESPCONN_ARG; - - /*Find the node depend on the espconn message*/ - value = espconn_find_connection(espconn, &pnode); - - if (value){ - /*protect for redisconnection*/ - if (pnode->preverse == NULL && espconn->state == ESPCONN_CLOSE) - return ESPCONN_INPROGRESS; - espconn_tcp_disconnect(pnode,0); //1 force, 0 normal - return ESPCONN_OK; - } else - return ESPCONN_ARG; -} - -/****************************************************************************** - * FunctionName : espconn_abort - * Description : Forcely abort with host - * Parameters : espconn -- the espconn used to disconnect the connection - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_abort(struct espconn *espconn) -{ - espconn_msg *pnode = NULL; - bool value = false; - - if (espconn == NULL) { - return ESPCONN_ARG;; - } else if (espconn ->type != ESPCONN_TCP) - return ESPCONN_ARG; - - /*Find the node depend on the espconn message*/ - value = espconn_find_connection(espconn, &pnode); - - if (value){ - /*protect for redisconnection*/ - if (espconn->state == ESPCONN_CLOSE) - return ESPCONN_INPROGRESS; - espconn_tcp_disconnect(pnode,1); //1 force, 0 normal - return ESPCONN_OK; - } else - return ESPCONN_ARG; -} - - -/****************************************************************************** - * FunctionName : espconn_get_packet_info - * Description : get the packet info with host - * Parameters : espconn -- the espconn used to disconnect the connection - * infoarg -- the packet info - * Returns : the errur code -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_get_packet_info(struct espconn *espconn, struct espconn_packet* infoarg) -{ - espconn_msg *pnode = NULL; - err_t err; - bool value = false; - - if (espconn == NULL || infoarg == NULL) { - return ESPCONN_ARG;; - } else if (espconn->type != ESPCONN_TCP) - return ESPCONN_ARG; - - /*Find the node depend on the espconn message*/ - value = espconn_find_connection(espconn, &pnode); - if (value) { - struct tcp_pcb *pcb = pnode->pcommon.pcb; - if (pcb == NULL) - return ESPCONN_ARG; - - pnode->pcommon.packet_info.packseq_nxt = pcb->rcv_nxt; - pnode->pcommon.packet_info.packseqno = pcb->snd_nxt; - pnode->pcommon.packet_info.snd_buf_size = pcb->snd_buf; - pnode->pcommon.packet_info.total_queuelen = TCP_SND_QUEUELEN; - pnode->pcommon.packet_info.snd_queuelen = pnode->pcommon.packet_info.total_queuelen - pcb->snd_queuelen; - os_memcpy(infoarg,(void*)&pnode->pcommon.packet_info, sizeof(struct espconn_packet)); - return ESPCONN_OK; - } else { - switch (espconn->state){ - case ESPCONN_CLOSE: - os_memcpy(infoarg,(void*)&pktinfo[0], sizeof(struct espconn_packet)); - err = ESPCONN_OK; - break; - case ESPCONN_NONE: - os_memcpy(infoarg,(void*)&pktinfo[1], sizeof(struct espconn_packet)); - err = ESPCONN_OK; - break; - default: - err = ESPCONN_ARG; - break; - } - return err; - } -} - -/****************************************************************************** - * FunctionName : espconn_set_opt - * Description : set the option for connections so that we don't end up bouncing - * all connections at the same time . - * Parameters : espconn -- the espconn used to set the connection - * opt -- the option for set - * Returns : the result -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_set_opt(struct espconn *espconn, uint8 opt) -{ - espconn_msg *pnode = NULL; - struct tcp_pcb *tpcb; - bool value = false; - - if (espconn == NULL) { - return ESPCONN_ARG;; - } else if (espconn->type != ESPCONN_TCP) - return ESPCONN_ARG; - - /*Find the node depend on the espconn message*/ - value = espconn_find_connection(espconn, &pnode); - if (value) { - pnode->pcommon.espconn_opt |= opt; - tpcb = pnode->pcommon.pcb; - if (espconn_delay_disabled(pnode)) - tcp_nagle_disable(tpcb); - - if (espconn_keepalive_disabled(pnode)) - espconn_keepalive_enable(tpcb); - - return ESPCONN_OK; - } else - return ESPCONN_ARG; -} - -/****************************************************************************** - * FunctionName : espconn_clear_opt - * Description : clear the option for connections so that we don't end up bouncing - * all connections at the same time . - * Parameters : espconn -- the espconn used to set the connection - * opt -- the option for clear - * Returns : the result -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_clear_opt(struct espconn *espconn, uint8 opt) -{ - espconn_msg *pnode = NULL; - struct tcp_pcb *tpcb; - bool value = false; - - if (espconn == NULL) { - return ESPCONN_ARG;; - } else if (espconn->type != ESPCONN_TCP) - return ESPCONN_ARG; - - /*Find the node depend on the espconn message*/ - value = espconn_find_connection(espconn, &pnode); - if (value) { - pnode->pcommon.espconn_opt &= ~opt; - tpcb = pnode->pcommon.pcb; - if (espconn_keepalive_enabled(pnode)) - espconn_keepalive_disable(tpcb); - - if (espconn_delay_enabled(pnode)) - tcp_nagle_enable(tpcb); - - return ESPCONN_OK; - } else - return ESPCONN_ARG; -} - -/****************************************************************************** - * FunctionName : espconn_set_keepalive - * Description : access level value for connection so that we set the value for - * keep alive - * Parameters : espconn -- the espconn used to set the connection - * level -- the connection's level - * value -- the value of time(s) - * Returns : access port value -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR espconn_set_keepalive(struct espconn *espconn, uint8 level, void* optarg) -{ - espconn_msg *pnode = NULL; - bool value = false; - sint8 ret = ESPCONN_OK; - - if (espconn == NULL || optarg == NULL) { - return ESPCONN_ARG;; - } else if (espconn->type != ESPCONN_TCP) - return ESPCONN_ARG; - - /*Find the node depend on the espconn message*/ - value = espconn_find_connection(espconn, &pnode); - if (value && espconn_keepalive_disabled(pnode)) { - struct tcp_pcb *pcb = pnode->pcommon.pcb; - switch (level){ - case ESPCONN_KEEPIDLE: - pcb->keep_idle = 1000 * (u32_t)(*(int*)optarg); - ret = ESPCONN_OK; - break; - case ESPCONN_KEEPINTVL: - pcb->keep_intvl = 1000 * (u32_t)(*(int*)optarg); - ret = ESPCONN_OK; - break; - case ESPCONN_KEEPCNT: - pcb->keep_cnt = (u32_t)(*(int*)optarg); - ret = ESPCONN_OK; - break; - default: - ret = ESPCONN_ARG; - break; - } - return ret; - } else - return ESPCONN_ARG; -} - -/****************************************************************************** - * FunctionName : espconn_get_keepalive - * Description : access level value for connection so that we get the value for - * keep alive - * Parameters : espconn -- the espconn used to get the connection - * level -- the connection's level - * Returns : access keep alive value -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg) -{ - espconn_msg *pnode = NULL; - bool value = false; - sint8 ret = ESPCONN_OK; - - if (espconn == NULL || optarg == NULL) { - return ESPCONN_ARG;; - } else if (espconn->type != ESPCONN_TCP) - return ESPCONN_ARG; - - /*Find the node depend on the espconn message*/ - value = espconn_find_connection(espconn, &pnode); - if (value && espconn_keepalive_disabled(pnode)) { - struct tcp_pcb *pcb = pnode->pcommon.pcb; - switch (level) { - case ESPCONN_KEEPIDLE: - *(int*)optarg = (int)(pcb->keep_idle/1000); - ret = ESPCONN_OK; - break; - case ESPCONN_KEEPINTVL: - *(int*)optarg = (int)(pcb->keep_intvl/1000); - ret = ESPCONN_OK; - break; - case ESPCONN_KEEPCNT: - *(int*)optarg = (int)(pcb->keep_cnt); - ret = ESPCONN_OK; - break; - default: - ret = ESPCONN_ARG; - break; - } - return ret; - } else - return ESPCONN_ARG; -} - -/****************************************************************************** - * FunctionName : espconn_delete - * Description : disconnect with host - * Parameters : espconn -- the espconn used to disconnect the connection - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_delete(struct espconn *espconn) -{ - espconn_msg *pnode = NULL; - bool value = false; - - if (espconn == NULL) { - return ESPCONN_ARG; - } else if (espconn ->type != ESPCONN_UDP) - return espconn_tcp_delete(espconn); - - /*Find the node depend on the espconn message*/ - value = espconn_find_connection(espconn, &pnode); - - if (value){ - espconn_udp_disconnect(pnode); - return ESPCONN_OK; - } else - return ESPCONN_ARG; -} - -/****************************************************************************** - * FunctionName : espconn_port - * Description : access port value for client so that we don't end up bouncing - * all connections at the same time . - * Parameters : none - * Returns : access port value -*******************************************************************************/ -uint32 ICACHE_FLASH_ATTR -espconn_port(void) -{ - uint32 port = 0; - static uint32 randnum = 0; - - do { - port = os_random(); - - if (port < 0) { - port = os_random() - port; - } - - port %= 0xc350; - - if (port < 0x400) { - port += 0x400; - } - - } while (port == randnum); - - randnum = port; - - return port; -} - -/****************************************************************************** - * FunctionName : espconn_gethostbyname - * Description : Resolve a hostname (string) into an IP address. - * Parameters : pespconn -- espconn to resolve a hostname - * hostname -- the hostname that is to be queried - * addr -- pointer to a ip_addr_t where to store the address if - * it is already cached in the dns_table (only valid if - * ESPCONN_OK is returned!) - * found -- a callback function to be called on success, failure - * or timeout (only if ERR_INPROGRESS is returned!) - * Returns : err_t return code - * - ESPCONN_OK if hostname is a valid IP address string or the host - * name is already in the local names table. - * - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server - * for resolution if no errors are present. - * - ESPCONN_ARG: dns client not initialized or invalid hostname -*******************************************************************************/ -err_t ICACHE_FLASH_ATTR -espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found) -{ - return dns_gethostbyname(hostname, addr, found, pespconn); -} - -/****************************************************************************** - * FunctionName : espconn_dns_setserver - * Description : Initialize one of the DNS servers. - * Parameters : numdns -- the index of the DNS server to set must - * be < DNS_MAX_SERVERS = 2 - * dnsserver -- IP address of the DNS server to set - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR -espconn_dns_setserver(u8_t numdns, ip_addr_t *dnsserver) -{ - dns_setserver(numdns,dnsserver); -} - diff --git a/tools/sdk/lwip/src/app/espconn_buf.c b/tools/sdk/lwip/src/app/espconn_buf.c deleted file mode 100644 index f91d1d23e..000000000 --- a/tools/sdk/lwip/src/app/espconn_buf.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * espconn_buf.c - * - * Created on: May 25, 2016 - * Author: liuhan - */ - -#include "lwip/memp.h" -#include "lwip/def.h" -#include "ets_sys.h" -#include "os_type.h" -#include "lwip/app/espconn_buf.h" - - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -#if (!defined(lwIP_unlikely)) -#define lwIP_unlikely(Expression) !!(Expression) -#endif - -#define lwIP_ASSERT(Expression) do{if(!(Expression)) {os_printf("%s %d\n", __func__, __LINE__);return;}}while(0) - -ringbuf_t ringbuf_new(size_t capacity) -{ - ringbuf_t rb = (ringbuf_t)os_zalloc(sizeof(struct ringbuf_t)); - if (rb){ - rb->size = capacity + 1; - rb->buf = (uint8*)os_zalloc(rb->size); - if (rb->buf){ - ringbuf_reset(rb); - }else{ - os_free(rb); - return NULL; - } - } - return rb; -} - -size_t ringbuf_buffer_size(const struct ringbuf_t *rb) -{ - return rb->size; -} - -void ringbuf_reset(ringbuf_t rb) -{ - rb ->head = rb->tail = rb->buf; -} - -void ringbuf_free(ringbuf_t *rb) -{ - lwIP_ASSERT(rb && *rb); - os_free((*rb)->buf); - os_free(*rb); - *rb = NULL; -} - -size_t ringbuf_capacity(const struct ringbuf_t *rb) -{ - return ringbuf_buffer_size(rb) - 1; -} - -static const uint8_t* ringbuf_end(const struct ringbuf_t *rb) -{ - return rb->buf + ringbuf_buffer_size(rb); -} - -size_t ringbuf_bytes_free(const struct ringbuf_t *rb) -{ - if (rb->head >= rb->tail){ - return ringbuf_capacity(rb) - (rb->head - rb->tail); - }else{ - return rb->tail - rb->head -1; - } -} - -size_t ringbuf_bytes_used(const struct ringbuf_t *rb) -{ - return ringbuf_capacity(rb) - ringbuf_bytes_free(rb); -} - -int ringbuf_is_full(const struct ringbuf_t *rb) -{ - return ringbuf_bytes_free(rb) == 0; -} - -int ringbuf_is_empty(const struct ringbuf_t *rb) -{ - return ringbuf_bytes_free(rb) == ringbuf_capacity(rb); -} - -const void* ringbuf_tail(const struct ringbuf_t *rb) -{ - return rb->tail; -} -const void* ringbuf_head(const struct ringbuf_t *rb) -{ - return rb->head; -} - -static uint8_t *ringbuf_nextp(ringbuf_t rb, const uint8_t *p) -{ - lwIP_ASSERT((p >= rb->buf) && (p < ringbuf_end(rb))); - return rb->buf + ((++p -rb->buf) % ringbuf_buffer_size(rb)); -} - -size_t ringbuf_findchr(const struct ringbuf_t *rb, int c, size_t offset) -{ - const uint8_t *bufend = ringbuf_end(rb); - size_t bytes_used = ringbuf_bytes_used(rb); - if (offset >= bytes_used) - return bytes_used; - - const uint8_t *start = rb ->buf + (((rb->tail - rb->buf) + offset) % ringbuf_buffer_size(rb)); - lwIP_ASSERT(bufend > start); - size_t n = LWIP_MIN(bufend - start, bytes_used - offset); - const uint8_t *found = (const uint8_t *)memchr(start, c, n); - if (found) - return offset + (found - start); - else - return ringbuf_findchr(rb, c, offset + n); -} - -size_t ringbuf_memset(ringbuf_t dst, int c, size_t len) -{ - const uint8_t *bufend = ringbuf_end(dst); - size_t nwritten = 0; - size_t count = LWIP_MIN(len, ringbuf_buffer_size(dst)); - int overflow = count > ringbuf_bytes_free(dst); - - while (nwritten != count){ - - lwIP_ASSERT(bufend > dst->head); - size_t n = LWIP_MIN(bufend - dst->head, count - nwritten); - os_memset(dst->head, c, n); - dst->head += n; - nwritten += n; - - if (dst->head == bufend) - dst->head = dst->buf; - } - - if (overflow){ - dst->tail = ringbuf_nextp(dst, dst->head); - lwIP_ASSERT(ringbuf_is_full(dst)); - } - - return nwritten; -} - -void *ringbuf_memcpy_into(ringbuf_t dst,const void *src, size_t count) -{ - const uint8_t *u8src = src; - const uint8_t *bufend = ringbuf_end(dst); - int overflow = count > ringbuf_bytes_free(dst); - size_t nread = 0; - - while (nread != count){ - lwIP_ASSERT(bufend > dst->head); - size_t n = LWIP_MIN(bufend - dst->head, count - nread); - os_memcpy(dst->head, u8src + nread, n); - dst->head += n; - nread += n; - - if (dst->head == bufend) - dst->head = dst->buf; - } - - if (overflow) { - dst->tail = ringbuf_nextp(dst, dst->head); - lwIP_ASSERT(ringbuf_is_full(dst)); - } - - return dst->head; -} - -void *ringbuf_memcpy_from(void *dst,ringbuf_t src, size_t count) -{ - size_t bytes_used = ringbuf_bytes_used(src); - - if (count > bytes_used) - return NULL; - - const uint8_t *u8dst = dst; - const uint8_t *bufend = ringbuf_end(src); - size_t nwritten = 0; - - while (nwritten != count){ - lwIP_ASSERT(bufend > src->tail); - size_t n = LWIP_MIN(bufend - src->tail, count - nwritten); - os_memcpy((uint8_t*)u8dst + nwritten, src->tail, n); - src->tail += n; - nwritten += n; - - if (src->tail == bufend) - src->tail = src->buf; - } - - lwIP_ASSERT(count + ringbuf_bytes_used(src) == bytes_used); - return src->tail; -} - - - diff --git a/tools/sdk/lwip/src/app/espconn_mdns.c b/tools/sdk/lwip/src/app/espconn_mdns.c deleted file mode 100644 index a29c64a54..000000000 --- a/tools/sdk/lwip/src/app/espconn_mdns.c +++ /dev/null @@ -1,134 +0,0 @@ -/****************************************************************************** - * Copyright 2013-2014 Espressif Systems (Wuxi) - * - * FileName: espconn_mdns.c - * - * Description: udp proto interface - * - * Modification history: - * 2014/3/31, v1.0 create this file. -*******************************************************************************/ - -#include "ets_sys.h" -#include "os_type.h" - -#include "lwip/mdns.h" - -/****************************************************************************** - * FunctionName : espconn_mdns_enable - * Description : join a multicast group - * Parameters : host_ip -- the ip address of udp server - * multicast_ip -- multicast ip given by user - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR -espconn_mdns_enable(void) -{ - mdns_enable(); -} -/****************************************************************************** - * FunctionName : espconn_mdns_disable - * Description : join a multicast group - * Parameters : host_ip -- the ip address of udp server - * multicast_ip -- multicast ip given by user - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR -espconn_mdns_disable(void) -{ - mdns_disable(); -} - -/****************************************************************************** - * FunctionName : espconn_mdns_set_hostname - * Description : join a multicast group - * Parameters : host_ip -- the ip address of udp server - * multicast_ip -- multicast ip given by user - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR -espconn_mdns_set_hostname(char *name) -{ - mdns_set_hostname(name); -} - -/****************************************************************************** - * FunctionName : espconn_mdns_init - * Description : join a multicast group - * Parameters : host_ip -- the ip address of udp server - * multicast_ip -- multicast ip given by user - * Returns : none -*******************************************************************************/ -char* ICACHE_FLASH_ATTR -espconn_mdns_get_hostname(void) -{ - return (char *)mdns_get_hostname(); -} -/****************************************************************************** - * FunctionName : espconn_mdns_get_servername - * Description : join a multicast group - * Parameters : info -- the info of mdns - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR -espconn_mdns_set_servername(const char *name) -{ - mdns_set_servername(name); -} -/****************************************************************************** - * FunctionName : espconn_mdns_get_servername - * Description : join a multicast group - * Parameters : info -- the info of mdns - * Returns : none -*******************************************************************************/ -char* ICACHE_FLASH_ATTR -espconn_mdns_get_servername(void) -{ - return (char *)mdns_get_servername(); -} -/****************************************************************************** - * FunctionName : mdns_server_register - * Description : join a multicast group - * Parameters : info -- the info of mdns - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR -espconn_mdns_server_register(void) -{ - mdns_server_register(); -} -/****************************************************************************** - * FunctionName : mdns_server_register - * Description : join a multicast group - * Parameters : info -- the info of mdns - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR -espconn_mdns_server_unregister(void) -{ - mdns_server_unregister(); -} -/****************************************************************************** - * FunctionName : espconn_mdns_init - * Description : join a multicast group - * Parameters : host_ip -- the ip address of udp server - * multicast_ip -- multicast ip given by user - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR -espconn_mdns_close(void) -{ - mdns_close(); -} -/****************************************************************************** - * FunctionName : espconn_mdns_init - * Description : join a multicast group - * Parameters : host_ip -- the ip address of udp server - * multicast_ip -- multicast ip given by user - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR -espconn_mdns_init(struct mdns_info *info) -{ - mdns_init(info); -} diff --git a/tools/sdk/lwip/src/app/espconn_tcp.c b/tools/sdk/lwip/src/app/espconn_tcp.c deleted file mode 100644 index 69c86c228..000000000 --- a/tools/sdk/lwip/src/app/espconn_tcp.c +++ /dev/null @@ -1,1479 +0,0 @@ -/****************************************************************************** - * Copyright 2013-2014 Espressif Systems (Wuxi) - * - * FileName: espconn_tcp.c - * - * Description: tcp proto interface - * - * Modification history: - * 2014/3/31, v1.0 create this file. -*******************************************************************************/ - -#include "lwip/netif.h" -#include "lwip/inet.h" -#include "netif/etharp.h" -#include "lwip/tcp.h" -#include "lwip/ip.h" -#include "lwip/init.h" -#include "lwip/tcp_impl.h" -#include "lwip/memp.h" - -#include "ets_sys.h" -#include "os_type.h" -//#include "os.h" -#include "lwip/mem.h" -#include "lwip/app/espconn_tcp.h" - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -extern espconn_msg *plink_active; -extern espconn_msg *pserver_list; -extern struct espconn_packet pktinfo[2]; -extern struct tcp_pcb ** const tcp_pcb_lists[]; - -os_event_t espconn_TaskQueue[espconn_TaskQueueLen]; - -static err_t -espconn_client_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); -static void -espconn_client_close(void *arg, struct tcp_pcb *pcb,u8 type); - -static err_t -espconn_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); -static void -espconn_server_close(void *arg, struct tcp_pcb *pcb,u8 type); - -///////////////////////////////common function///////////////////////////////// -/****************************************************************************** - * FunctionName : espconn_kill_oldest - * Description : kill the oldest TCP block - * Parameters : none - * Returns : none -*******************************************************************************/ -static void ICACHE_FLASH_ATTR -espconn_kill_oldest(void) -{ - struct tcp_pcb *pcb, *inactive; - u32_t inactivity; - - inactivity = 0; - inactive = NULL; - /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ - for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { - if ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) { - inactivity = tcp_ticks - pcb->tmr; - inactive = pcb; - } - } - if (inactive != NULL) { - tcp_abort(inactive); - } - - /* Go through the list of FIN_WAIT_2 pcbs and get the oldest pcb. */ - inactivity = 0; - inactive = NULL; - for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - if (pcb->state == FIN_WAIT_1 || pcb->state == FIN_WAIT_2){ - if ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) { - inactivity = tcp_ticks - pcb->tmr; - inactive = pcb; - } - } - } - /*Purges the PCB, removes it from a PCB list and frees the memory*/ - if (inactive != NULL) { - tcp_pcb_remove(&tcp_active_pcbs, inactive); - memp_free(MEMP_TCP_PCB, inactive); - } - - /* Go through the list of LAST_ACK pcbs and get the oldest pcb. */ - inactivity = 0; - inactive = NULL; - for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - if (pcb->state == LAST_ACK) { - if ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) { - inactivity = tcp_ticks - pcb->tmr; - inactive = pcb; - } - } - } - /*Purges the PCB, removes it from a PCB list and frees the memory*/ - if (inactive != NULL) { - tcp_pcb_remove(&tcp_active_pcbs, inactive); - memp_free(MEMP_TCP_PCB, inactive); - } -} - -/****************************************************************************** - * FunctionName : espconn_kill_oldest_pcb - * Description : find the oldest TCP block by state - * Parameters : none - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR espconn_kill_oldest_pcb(void) -{ - struct tcp_pcb *cpcb = NULL; - uint8 i = 0; - uint8 num_tcp_fin = 0; - for(i = 2; i < 4; i ++){ - for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { - if (cpcb->state == TIME_WAIT){ - num_tcp_fin ++; - if (num_tcp_fin == MEMP_NUM_TCP_PCB) - break; - } - - if (cpcb->state == FIN_WAIT_1 || cpcb->state == FIN_WAIT_2 || cpcb->state == LAST_ACK){ - num_tcp_fin++; - if (num_tcp_fin == MEMP_NUM_TCP_PCB) - break; - } - } - - if (num_tcp_fin == MEMP_NUM_TCP_PCB){ - num_tcp_fin = 0; - espconn_kill_oldest(); - } else if (cpcb == NULL){ - num_tcp_fin = 0; - } - } -} - -/****************************************************************************** - * FunctionName : espconn_kill_pcb - * Description : kill all the TCP block by port - * Parameters : none - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR espconn_kill_pcb(u16_t port) -{ - struct tcp_pcb *cpcb = NULL; - uint8 i = 0; - struct tcp_pcb *inactive = NULL; - struct tcp_pcb *prev = NULL; - u8_t pcb_remove; - /* Check if the address already is in use (on all lists) */ - for (i = 1; i < 4; i++) { - cpcb = *tcp_pcb_lists[i]; - while(cpcb != NULL){ - pcb_remove = 0; - if (cpcb->local_port == port) { - ++pcb_remove; - } - /* If the PCB should be removed, do it. */ - if (pcb_remove) { - /* Remove PCB from tcp_pcb_lists list. */ - inactive = cpcb; - cpcb = inactive->next; - tcp_pcb_remove(tcp_pcb_lists[i], inactive); - memp_free(MEMP_TCP_PCB, inactive); - } else { - cpcb = cpcb->next; - } - } - } -} - -/****************************************************************************** - * FunctionName : espconn_find_current_pcb - * Description : find the TCP block which option - * Parameters : pcurrent_msg -- the node in the list which active - * Returns : TCP block point -*******************************************************************************/ -struct tcp_pcb *ICACHE_FLASH_ATTR espconn_find_current_pcb(espconn_msg *pcurrent_msg) -{ - uint16 local_port = pcurrent_msg->pcommon.local_port; - uint32 local_ip = pcurrent_msg->pcommon.local_ip; - uint16 remote_port = pcurrent_msg->pcommon.remote_port; - uint32 remote_ip = *((uint32*)&pcurrent_msg->pcommon.remote_ip); - struct tcp_pcb *find_pcb = NULL; - if (pcurrent_msg ->preverse == NULL){/*Find the server's TCP block*/ - if (local_ip == 0|| local_port == 0) return pcurrent_msg->pcommon.pcb; - - for (find_pcb = tcp_active_pcbs; find_pcb != NULL; find_pcb = find_pcb->next){ - if ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.addr == remote_ip) && - (find_pcb->local_port == local_port) && (find_pcb->local_ip.addr == local_ip)) - return find_pcb; - } - - for (find_pcb = tcp_tw_pcbs; find_pcb != NULL; find_pcb = find_pcb->next){ - if ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.addr == remote_ip) && - (find_pcb->local_port == local_port) && (find_pcb->local_ip.addr == local_ip)) - return find_pcb; - } - } else {/*Find the client's TCP block*/ - if (remote_ip == 0|| remote_port == 0) return pcurrent_msg->pcommon.pcb; - - for (find_pcb = tcp_active_pcbs; find_pcb != NULL; find_pcb = find_pcb->next){ - if ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.addr == remote_ip)) - return find_pcb; - } - - for (find_pcb = tcp_tw_pcbs; find_pcb != NULL; find_pcb = find_pcb->next){ - if ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.addr == remote_ip)) - return find_pcb; - } - } - return NULL; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_memp_free - * Description : frees the connection memory in the server mode - * Parameters : arg -- Additional argument to pass to the function - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR espconn_tcp_memp_free(espconn_msg *pmemp) -{ - struct espconn *espconn = NULL; - if (pmemp == NULL) - return; - - if (pmemp->espconn_mode == ESPCONN_TCPSERVER_MODE){ - if (pmemp->pespconn != NULL && pmemp->pespconn->proto.tcp != NULL) - os_free(pmemp->pespconn->proto.tcp); - pmemp->pespconn->proto.tcp = NULL; - - os_free(pmemp->pespconn); - pmemp->pespconn = NULL; - } - - if (pmemp->readbuf != NULL){ - ringbuf_free(&pmemp->readbuf); - } - os_free(pmemp); - pmemp = NULL; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_reconnect - * Description : reconnect with host - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ -static void ICACHE_FLASH_ATTR -espconn_tcp_reconnect(void *arg) -{ - espconn_msg *precon_cb = arg; - sint8 re_err = 0; - espconn_buf *perr_buf = NULL; - espconn_buf *perr_back = NULL; - espconn_kill_oldest_pcb(); - if (precon_cb != NULL) { - struct espconn *espconn = precon_cb->preverse; - - re_err = precon_cb->pcommon.err; - if (precon_cb->pespconn != NULL){ - if (espconn != NULL){/*Process the server's message block*/ - if (precon_cb->pespconn->proto.tcp != NULL){ - espconn_copy_partial(espconn, precon_cb->pespconn); - } - } else {/*Process the client's message block*/ - espconn = precon_cb->pespconn; - } - } - - /*to prevent memory leaks, ensure that each allocated is deleted*/ - perr_buf = precon_cb->pcommon.pbuf; - while (perr_buf != NULL){ - perr_back = perr_buf; - perr_buf = perr_back->pnext; - espconn_pbuf_delete(&precon_cb->pcommon.pbuf,perr_back); - os_free(perr_back); - perr_back = NULL; - } - os_bzero(&pktinfo[1], sizeof(struct espconn_packet)); - os_memcpy(&pktinfo[1], (void*)&precon_cb->pcommon.packet_info, sizeof(struct espconn_packet)); - - if (espconn && espconn->proto.tcp && espconn->proto.tcp->reconnect_callback != NULL) { - espconn->proto.tcp->reconnect_callback(espconn, re_err); - } - - /*frees the connection memory*/ - espconn_tcp_memp_free(precon_cb); - } else { - espconn_printf("espconn_tcp_reconnect err\n"); - } -} - -/****************************************************************************** - * FunctionName : espconn_tcp_disconnect - * Description : disconnect with host - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ -static void ICACHE_FLASH_ATTR -espconn_tcp_disconnect_successful(void *arg) -{ - espconn_msg *pdiscon_cb = arg; - sint8 dis_err = 0; - espconn_buf *pdis_buf = NULL; - espconn_buf *pdis_back = NULL; - espconn_kill_oldest_pcb(); - if (pdiscon_cb != NULL) { - struct espconn *espconn = pdiscon_cb->preverse; - - dis_err = pdiscon_cb->pcommon.err; - if (pdiscon_cb->pespconn != NULL){ - struct tcp_pcb *pcb = NULL; - if (espconn != NULL){/*Process the server's message block*/ - if (pdiscon_cb->pespconn->proto.tcp != NULL && espconn->proto.tcp){ - espconn_copy_partial(espconn, pdiscon_cb->pespconn); - } - } else {/*Process the client's message block*/ - espconn = pdiscon_cb->pespconn; - } - - /*process the current TCP block*/ - pcb = espconn_find_current_pcb(pdiscon_cb); - if (pcb != NULL){ - if (espconn_reuse_disabled(pdiscon_cb)) { - struct tcp_pcb *cpcb = NULL; - struct tcp_pcb *prev = NULL; - u8_t pcb_remove; - espconn_printf("espconn_tcp_disconnect_successful %d, %d\n", pcb->state, pcb->local_port); - cpcb = tcp_tw_pcbs; - while (cpcb != NULL) { - pcb_remove = 0; - if (cpcb->local_port == pcb->local_port) { - ++pcb_remove; - } - /* If the PCB should be removed, do it. */ - if (pcb_remove) { - struct tcp_pcb *backup_pcb = NULL; - tcp_pcb_purge(cpcb); - /* Remove PCB from tcp_tw_pcbs list. */ - if (prev != NULL) { - LWIP_ASSERT("espconn_tcp_delete: middle cpcb != tcp_tw_pcbs",cpcb != tcp_tw_pcbs); - prev->next = cpcb->next; - } else { - /* This PCB was the first. */ - LWIP_ASSERT("espconn_tcp_delete: first cpcb == tcp_tw_pcbs",tcp_tw_pcbs == cpcb); - tcp_tw_pcbs = cpcb->next; - } - backup_pcb = cpcb; - cpcb = cpcb->next; - memp_free(MEMP_TCP_PCB, backup_pcb); - } else { - prev = cpcb; - cpcb = cpcb->next; - } - } - - } else { - tcp_arg(pcb, NULL); - tcp_err(pcb, NULL); - } - } - } - - /*to prevent memory leaks, ensure that each allocated is deleted*/ - pdis_buf = pdiscon_cb->pcommon.pbuf; - while (pdis_buf != NULL) { - pdis_back = pdis_buf; - pdis_buf = pdis_back->pnext; - espconn_pbuf_delete(&pdiscon_cb->pcommon.pbuf, pdis_back); - os_free(pdis_back); - pdis_back = NULL; - } - os_bzero(&pktinfo[0], sizeof(struct espconn_packet)); - os_memcpy(&pktinfo[0], (void*)&pdiscon_cb->pcommon.packet_info, sizeof(struct espconn_packet)); - - if (espconn->proto.tcp && espconn->proto.tcp->disconnect_callback != NULL) { - espconn->proto.tcp->disconnect_callback(espconn); - } - - /*frees the connection memory*/ - espconn_tcp_memp_free(pdiscon_cb); - } else { - espconn_printf("espconn_tcp_disconnect err\n"); - } -} - -/****************************************************************************** - * FunctionName : espconn_Task - * Description : espconn processing task - * Parameters : events -- contain the espconn processing data - * Returns : none -*******************************************************************************/ -static void ICACHE_FLASH_ATTR -espconn_Task(os_event_t *events) -{ - espconn_msg *plist = NULL; - bool active_flag = false; - espconn_msg *task_msg = NULL; - struct espconn *pespconn = NULL; - - task_msg = (espconn_msg *) events->par; - /*find the active connection node*/ - for (plist = plink_active; plist != NULL; plist = plist->pnext){ - if (task_msg == plist) { - active_flag = true; - break; - } - } - - if (active_flag){ - switch (events->sig) { - case SIG_ESPCONN_WRITE: { - pespconn = task_msg->pespconn; - if (pespconn == NULL) { - return; - } - - if (pespconn->proto.tcp->write_finish_fn != NULL) { - pespconn->proto.tcp->write_finish_fn(pespconn); - } - } - break; - case SIG_ESPCONN_ERRER: - /*remove the node from the client's active connection list*/ - espconn_list_delete(&plink_active, task_msg); - espconn_tcp_reconnect(task_msg); - break; - case SIG_ESPCONN_CLOSE: - /*remove the node from the client's active connection list*/ - espconn_list_delete(&plink_active, task_msg); - espconn_tcp_disconnect_successful(task_msg); - break; - default: - break; - } - } -} - -/****************************************************************************** - * FunctionName : espconn_tcp_sent - * Description : sent data for client or server - * Parameters : void *arg -- client or server to send - * uint8* psent -- Data to send - * uint16 length -- Length of data to send - * Returns : return espconn error code. - * - ESPCONN_OK. Successful. No error occured. - * - ESPCONN_MEM. Out of memory. - * - ESPCONN_RTE. Could not find route to destination address. - * - More errors could be returned by lower protocol layers. -*******************************************************************************/ -err_t ICACHE_FLASH_ATTR -espconn_tcp_sent(void *arg, uint8 *psent, uint16 length) -{ - espconn_msg *ptcp_sent = arg; - struct tcp_pcb *pcb = NULL; - err_t err = 0; - u16_t len = 0; - u8_t data_to_send = false; - - espconn_printf("espconn_tcp_sent ptcp_sent %p psent %p length %d\n", ptcp_sent, psent, length); - - /*Check the parameters*/ - if (ptcp_sent == NULL || psent == NULL || length == 0) { - return ESPCONN_ARG; - } - - /*Set the packet length depend on the sender buffer space*/ - pcb = ptcp_sent->pcommon.pcb; - if (tcp_sndbuf(pcb) < length) { - len = tcp_sndbuf(pcb); - } else { - len = length; - LWIP_ASSERT("length did not fit into uint16!", (len == length)); - } - - if (len > (2*pcb->mss)) { - len = 2*pcb->mss; - } - - /*Write data for sending, but does not send it immediately*/ - do { - espconn_printf("espconn_tcp_sent writing %d bytes %p\n", len, pcb); - if (espconn_copy_disabled(ptcp_sent)) - err = tcp_write(pcb, psent, len, 1); - else - err = tcp_write(pcb, psent, len, 0); - - if (err == ERR_MEM) { - if(len < 3) - len--; - else - len /= 2; - } - - } while (err == ERR_MEM && len > 0); - - /*Find out what we can send and send it, offset the buffer point for next send*/ - if (err == ERR_OK) { - ptcp_sent->pcommon.ptail->punsent = psent + len; - ptcp_sent->pcommon.ptail->unsent = length - len; - err = tcp_output(pcb); - /*If enable the copy option, change the flag for next write*/ - if (espconn_copy_disabled(ptcp_sent)){ - if (ptcp_sent->pcommon.ptail->unsent == 0) { - ptcp_sent->pcommon.write_flag = true; - ets_post(espconn_TaskPrio, SIG_ESPCONN_WRITE, (uint32_t)ptcp_sent); - } - } - espconn_printf("espconn_tcp_sent %d\n", err); - } - return err; -} - -/****************************************************************************** - * FunctionName : espconn_close - * Description : The connection has been successfully closed. - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR espconn_tcp_disconnect(espconn_msg *pdiscon,u8 type) -{ - if (pdiscon != NULL){ - /*disconnect with the host by send the FIN frame*/ - if (pdiscon->preverse != NULL) - espconn_server_close(pdiscon, pdiscon->pcommon.pcb,type); - else - espconn_client_close(pdiscon, pdiscon->pcommon.pcb,type); - } else{ - espconn_printf("espconn_tcp_disconnect err.\n"); - } -} - -///////////////////////////////client function///////////////////////////////// -/****************************************************************************** - * FunctionName : espconn_client_close - * Description : The connection shall be actively closed. - * Parameters : pcb -- Additional argument to pass to the callback function - * pcb -- the pcb to close - * Returns : none -*******************************************************************************/ -static void ICACHE_FLASH_ATTR -espconn_client_close(void *arg, struct tcp_pcb *pcb, u8 type) -{ - err_t err; - espconn_msg *pclose = arg; - - pclose->pcommon.pcb = pcb; - /*avoid recalling the disconnect function*/ - tcp_recv(pcb, NULL); - - if(type == 0) - err = tcp_close(pcb); - else { - tcp_sent(pcb, NULL); - tcp_err(pcb, NULL); - tcp_abort(pcb); - err = ERR_OK; - } - - if (err != ERR_OK) { - /* closing failed, try again later */ - tcp_recv(pcb, espconn_client_recv); - } else { - /* closing succeeded */ - if (type == 0) { - tcp_sent(pcb, NULL); - tcp_err(pcb, NULL); - } - /*switch the state of espconn for application process*/ - pclose->pespconn->state = ESPCONN_CLOSE; - ets_post(espconn_TaskPrio, SIG_ESPCONN_CLOSE, (uint32_t)pclose); - } -} - -//***********Code for WIFI_BLOCK from upper************** -sint8 ICACHE_FLASH_ATTR -espconn_recv_hold(struct espconn *pespconn) -{ - //1st, according to espconn code, have to find out the escpconn_msg by pespconn; - espconn_msg *pnode = NULL; - bool value = false; - if (pespconn == NULL) { - return ESPCONN_ARG; - } - value = espconn_find_connection(pespconn, &pnode); - if(value != true) - { - os_printf("RecvHold, By pespconn,find conn_msg fail\n"); - return ESPCONN_ARG; - } - - //2nd, the actual operation - if(pnode->recv_hold_flag == 0) - { - pnode->recv_hold_flag = 1; - pnode->recv_holded_buf_Len = 0; - } - return ESPCONN_OK; -} - -sint8 ICACHE_FLASH_ATTR -espconn_recv_unhold(struct espconn *pespconn) -{ - //1st, according to espconn code, have to find out the escpconn_msg by pespconn; - espconn_msg *pnode = NULL; - bool value = false; - if (pespconn == NULL) { - return ESPCONN_ARG; - } - value = espconn_find_connection(pespconn, &pnode); - if(value != true) - { - os_printf("RecvHold, By pespconn,find conn_msg fail\n"); - return ESPCONN_ARG; - } - - //2nd, the actual operation - if(pnode->recv_hold_flag == 1) - { - if(pespconn->type == ESPCONN_TCP) { - tcp_recved(pnode->pcommon.pcb, pnode->recv_holded_buf_Len); - } - pnode->recv_holded_buf_Len = 0; - pnode->recv_hold_flag = 0; - } - return ESPCONN_OK; -} - -//***********Code for WIFI_BLOCK from upper************** -sint8 ICACHE_FLASH_ATTR -espconn_lock_recv(espconn_msg *plockmsg) -{ - if (plockmsg == NULL || plockmsg->pespconn == NULL) { - return ESPCONN_ARG; - } - - if (plockmsg->pespconn->recv_callback == NULL){ - if (plockmsg->readbuf == NULL){ - plockmsg->readbuf = ringbuf_new(TCP_WND); - if (plockmsg->readbuf == NULL) - return ESPCONN_MEM; - } - return espconn_recv_hold(plockmsg->pespconn); - } - - return ESPCONN_OK; -} - -sint8 ICACHE_FLASH_ATTR -espconn_unlock_recv(espconn_msg *punlockmsg) -{ - if (punlockmsg == NULL || punlockmsg->pespconn == NULL) { - return ESPCONN_ARG; - } - - if (punlockmsg->pespconn->recv_callback != NULL) - return espconn_recv_unhold(punlockmsg->pespconn); - - return ESPCONN_OK; -} -/****************************************************************************** - * FunctionName : espconn_client_recv - * Description : Data has been received on this pcb. - * Parameters : arg -- Additional argument to pass to the callback function - * pcb -- The connection pcb which received data - * p -- The received data (or NULL when the connection has been closed!) - * err -- An error code if there has been an error receiving - * Returns : ERR_ABRT: if you have called tcp_abort from within the function! -*******************************************************************************/ -static err_t ICACHE_FLASH_ATTR -espconn_client_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) -{ - espconn_msg *precv_cb = arg; - - tcp_arg(pcb, arg); - /*lock the window because of application layer don't need the data*/ - espconn_lock_recv(precv_cb); - - if (p != NULL) { - /*To update and advertise a larger window*/ - if(precv_cb->recv_hold_flag == 0) - tcp_recved(pcb, p->tot_len); - else - precv_cb->recv_holded_buf_Len += p->tot_len; - } - - if (precv_cb->pespconn->recv_callback != NULL){ - if (err == ERR_OK && p != NULL) { - char *pdata = NULL; - u16_t length = 0; - /*Copy the contents of a packet buffer to an application buffer. - *to prevent memory leaks, ensure that each allocated is deleted*/ - pdata = (char *)os_zalloc(p ->tot_len + 1); - length = pbuf_copy_partial(p, pdata, p ->tot_len, 0); - pbuf_free(p); - - if (length != 0) { - /*switch the state of espconn for application process*/ - precv_cb->pespconn ->state = ESPCONN_READ; - precv_cb->pcommon.pcb = pcb; - precv_cb->pespconn->recv_callback(precv_cb->pespconn, pdata, length); - - /*switch the state of espconn for next packet copy*/ - if (pcb->state == ESTABLISHED) - precv_cb->pespconn ->state = ESPCONN_CONNECT; - } - - /*to prevent memory leaks, ensure that each allocated is deleted*/ - os_free(pdata); - pdata = NULL; - } - } else{ - /*unregister receive function*/ - struct pbuf *pthis = NULL; - for (pthis = p; pthis != NULL; pthis = pthis->next) { - ringbuf_memcpy_into(precv_cb->readbuf, pthis->payload, pthis->len); - pbuf_free(pthis); - } - } - - if (err == ERR_OK && p == NULL) { - espconn_client_close(precv_cb, pcb,0); - } - - return ERR_OK; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_write - * Description : write the packet which in the active connection's list. - * Parameters : arg -- the node pointer which reverse the packet - * Returns : ESPCONN_MEM: memory error - * ESPCONN_OK:have enough space for write packet -*******************************************************************************/ -err_t ICACHE_FLASH_ATTR espconn_tcp_write(void *arg) -{ - espconn_msg *pwrite = arg; - err_t err = ERR_OK; - struct tcp_pcb *pcb = pwrite->pcommon.pcb; - /*for one active connection,limit the sender buffer space*/ - if (tcp_nagle_disabled(pcb) && (pcb->snd_queuelen >= TCP_SND_QUEUELEN)) - return ESPCONN_MEM; - - while (tcp_sndbuf(pcb) != 0){ - if (pwrite->pcommon.ptail != NULL) { - /*Find the node whether in the list's tail or not*/ - if (pwrite->pcommon.ptail->unsent == 0) { - pwrite->pcommon.ptail = pwrite->pcommon.ptail->pnext; - continue; - } - - /*Send the packet for the active connection*/ - err = espconn_tcp_sent(pwrite, pwrite->pcommon.ptail->punsent,pwrite->pcommon.ptail->unsent); - if (err != ERR_OK) - break; - } else - break; - } - return err; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_reconnect - * Description : reconnect with host - * Parameters : arg -- Additional argument to pass to the callback function - * Returns : none -*******************************************************************************/ -static void ICACHE_FLASH_ATTR espconn_tcp_finish(void *arg) -{ - espconn_msg *pfinish = arg; - espconn_buf *premove = NULL; - uint16 len = 0; - espconn_tcp_write(pfinish); - while (pfinish->pcommon.pbuf != NULL){ - premove = pfinish->pcommon.pbuf; - pfinish->pcommon.pbuf->tot_len += len; - /*application packet has been sent and acknowledged by the remote host, - * to prevent memory leaks, ensure that each allocated is deleted*/ - if (premove->tot_len >= premove->len){ - espconn_pbuf_delete(&pfinish->pcommon.pbuf,premove); - len = premove->tot_len - premove->len; - pfinish->pcommon.packet_info.sent_length = premove->len; - os_free(premove); - premove = NULL; - pfinish->pespconn->state = ESPCONN_CONNECT; - if (pfinish->pespconn->sent_callback != NULL) { - pfinish->pespconn->sent_callback(pfinish->pespconn); - } - pfinish->pcommon.packet_info.sent_length = len; - } else - break; - } -} - -/****************************************************************************** - * FunctionName : espconn_client_sent - * Description : Data has been sent and acknowledged by the remote host. - * This means that more data can be sent. - * Parameters : arg -- Additional argument to pass to the callback function - * pcb -- The connection pcb for which data has been acknowledged - * len -- The amount of bytes acknowledged - * Returns : ERR_OK: try to send some data by calling tcp_output - * ERR_ABRT: if you have called tcp_abort from within the function! -*******************************************************************************/ -static err_t ICACHE_FLASH_ATTR -espconn_client_sent(void *arg, struct tcp_pcb *pcb, u16_t len) -{ - espconn_msg *psent_cb = arg; - - psent_cb->pcommon.pcb = pcb; - psent_cb->pcommon.pbuf->tot_len += len; - psent_cb->pcommon.packet_info.sent_length = len; - - /*Send more data for one active connection*/ - espconn_tcp_finish(psent_cb); - - return ERR_OK; -} - -/****************************************************************************** - * FunctionName : espconn_client_err - * Description : The pcb had an error and is already deallocated. - * The argument might still be valid (if != NULL). - * Parameters : arg -- Additional argument to pass to the callback function - * err -- Error code to indicate why the pcb has been closed - * Returns : none -*******************************************************************************/ -static void ICACHE_FLASH_ATTR -espconn_client_err(void *arg, err_t err) -{ - espconn_msg *perr_cb = arg; - struct tcp_pcb *pcb = NULL; - LWIP_UNUSED_ARG(err); - - if (perr_cb != NULL) { - pcb = perr_cb->pcommon.pcb; - perr_cb->pespconn->state = ESPCONN_CLOSE; - espconn_printf("espconn_client_err %d %d %d\n", pcb->state, pcb->nrtx, err); - -// /*remove the node from the client's active connection list*/ -// espconn_list_delete(&plink_active, perr_cb); - - /*Set the error code depend on the error type and control block state*/ - if (err == ERR_ABRT) { - switch (pcb->state) { - case SYN_SENT: - if (pcb->nrtx == TCP_SYNMAXRTX) { - perr_cb->pcommon.err = ESPCONN_CONN; - } else { - perr_cb->pcommon.err = err; - } - - break; - - case ESTABLISHED: - if (pcb->nrtx == TCP_MAXRTX) { - perr_cb->pcommon.err = ESPCONN_TIMEOUT; - } else { - perr_cb->pcommon.err = err; - } - break; - - case FIN_WAIT_1: - if (pcb->nrtx == TCP_MAXRTX) { - perr_cb->pcommon.err = ESPCONN_CLSD; - } else { - perr_cb->pcommon.err = err; - } - break; - case FIN_WAIT_2: - perr_cb->pcommon.err = ESPCONN_CLSD; - break; - case CLOSED: - perr_cb->pcommon.err = ESPCONN_CONN; - break; - } - } else { - perr_cb->pcommon.err = err; - } - /*post the singer to the task for processing the connection*/ - ets_post(espconn_TaskPrio, SIG_ESPCONN_ERRER, (uint32_t)perr_cb); - } -} - -/****************************************************************************** - * FunctionName : espconn_client_connect - * Description : A new incoming connection has been connected. - * Parameters : arg -- Additional argument to pass to the callback function - * tpcb -- The connection pcb which is connected - * err -- An unused error code, always ERR_OK currently - * Returns : connection result -*******************************************************************************/ -static err_t ICACHE_FLASH_ATTR -espconn_client_connect(void *arg, struct tcp_pcb *tpcb, err_t err) -{ - espconn_msg *pcon = arg; - - espconn_printf("espconn_client_connect pcon %p tpcb %p\n", pcon, tpcb); - if (err == ERR_OK){ - /*Reserve the remote information for current active connection*/ - pcon->pespconn->state = ESPCONN_CONNECT; - pcon->pcommon.err = err; - pcon->pcommon.pcb = tpcb; - pcon->pcommon.local_port = tpcb->local_port; - pcon->pcommon.local_ip = tpcb->local_ip.addr; - pcon->pcommon.remote_port = tpcb->remote_port; - pcon->pcommon.remote_ip[0] = ip4_addr1_16(&tpcb->remote_ip); - pcon->pcommon.remote_ip[1] = ip4_addr2_16(&tpcb->remote_ip); - pcon->pcommon.remote_ip[2] = ip4_addr3_16(&tpcb->remote_ip); - pcon->pcommon.remote_ip[3] = ip4_addr4_16(&tpcb->remote_ip); - pcon->pcommon.write_flag = true; - tcp_arg(tpcb, (void *) pcon); - - /*Set the specify function that should be called - * when TCP data has been successfully delivered, - * when active connection receives data*/ - tcp_sent(tpcb, espconn_client_sent); - tcp_recv(tpcb, espconn_client_recv); - /*Disable Nagle algorithm default*/ - tcp_nagle_disable(tpcb); - /*Default set the total number of espconn_buf on the unsent lists for one*/ - espconn_tcp_set_buf_count(pcon->pespconn, 1); - - if (pcon->pespconn->proto.tcp->connect_callback != NULL) { - pcon->pespconn->proto.tcp->connect_callback(pcon->pespconn); - } - - /*Enable keep alive option*/ - if (espconn_keepalive_disabled(pcon)) - espconn_keepalive_enable(tpcb); - -// /*lock the window because of application layer don't need the data*/ -// espconn_lock_recv(pcon); - } else{ - os_printf("err in host connected (%s)\n",lwip_strerr(err)); - } - return err; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_client - * Description : Initialize the client: set up a connect PCB and bind it to - * the defined port - * Parameters : espconn -- the espconn used to build client - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_tcp_client(struct espconn *espconn) -{ - struct tcp_pcb *pcb = NULL; - struct ip_addr ipaddr; - espconn_msg *pclient = NULL; - - /*Creates a new client control message*/ - pclient = (espconn_msg *)os_zalloc(sizeof(espconn_msg)); - if (pclient == NULL){ - return ESPCONN_MEM; - } - - /*Set an IP address given for Little-endian.*/ - IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0], - espconn->proto.tcp->remote_ip[1], - espconn->proto.tcp->remote_ip[2], - espconn->proto.tcp->remote_ip[3]); - - /*Creates a new TCP protocol control block*/ - pcb = tcp_new(); - - if (pcb == NULL) { - /*to prevent memory leaks, ensure that each allocated is deleted*/ - os_free(pclient); - pclient = NULL; - return ESPCONN_MEM; - } else { - - /*insert the node to the active connection list*/ - espconn_list_creat(&plink_active, pclient); - tcp_arg(pcb, (void *)pclient); - tcp_err(pcb, espconn_client_err); - pclient->preverse = NULL; - pclient->pespconn = espconn; - pclient->pespconn->state = ESPCONN_WAIT; - pclient->pcommon.pcb = pcb; - tcp_bind(pcb, IP_ADDR_ANY, pclient->pespconn->proto.tcp->local_port); -#if 0 - pclient->pcommon.err = tcp_bind(pcb, IP_ADDR_ANY, pclient->pespconn->proto.tcp->local_port); - if (pclient->pcommon.err != ERR_OK){ - /*remove the node from the client's active connection list*/ - espconn_list_delete(&plink_active, pclient); - memp_free(MEMP_TCP_PCB, pcb); - os_free(pclient); - pclient = NULL; - return ERR_USE; - } -#endif - /*Establish the connection*/ - pclient->espconn_mode = ESPCONN_TCPCLIENT_MODE; - pclient->pcommon.err = tcp_connect(pcb, &ipaddr, - pclient->pespconn->proto.tcp->remote_port, espconn_client_connect); - if (pclient->pcommon.err == ERR_RTE){ - /*remove the node from the client's active connection list*/ - espconn_list_delete(&plink_active, pclient); - espconn_kill_pcb(pcb->local_port); - os_free(pclient); - pclient = NULL; - return ESPCONN_RTE; - } - return pclient->pcommon.err; - } -} - -///////////////////////////////server function///////////////////////////////// -/****************************************************************************** - * FunctionName : espconn_server_close - * Description : The connection shall be actively closed. - * Parameters : arg -- Additional argument to pass to the callback function - * pcb -- the pcb to close - * Returns : none -*******************************************************************************/ -static void ICACHE_FLASH_ATTR -espconn_server_close(void *arg, struct tcp_pcb *pcb,u8 type) -{ - err_t err; - espconn_msg *psclose = arg; - - psclose->pcommon.pcb = pcb; - /*avoid recalling the disconnect function*/ - tcp_recv(pcb, NULL); - - if(type ==0) - err = tcp_close(pcb); - else { - tcp_poll(pcb, NULL, 0); - tcp_sent(pcb, NULL); - tcp_err(pcb, NULL); - tcp_abort(pcb); - err = ERR_OK; - } - - if (err != ERR_OK) { - /* closing failed, try again later */ - tcp_recv(pcb, espconn_server_recv); - } else { - /* closing succeeded */ - if (type == 0) { - tcp_poll(pcb, NULL, 0); - tcp_sent(pcb, NULL); - tcp_err(pcb, NULL); - } - /*switch the state of espconn for application process*/ - psclose->pespconn->state = ESPCONN_CLOSE; - ets_post(espconn_TaskPrio, SIG_ESPCONN_CLOSE, (uint32_t)psclose); - } -} - -/****************************************************************************** - * FunctionName : espconn_server_recv - * Description : Data has been received on this pcb. - * Parameters : arg -- Additional argument to pass to the callback function - * pcb -- The connection pcb which received data - * p -- The received data (or NULL when the connection has been closed!) - * err -- An error code if there has been an error receiving - * Returns : ERR_ABRT: if you have called tcp_abort from within the function! -*******************************************************************************/ -static err_t ICACHE_FLASH_ATTR -espconn_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) -{ - espconn_msg *precv_cb = arg; - - tcp_arg(pcb, arg); - espconn_printf("server has application data received: %d\n", system_get_free_heap_size()); - /*lock the window because of application layer don't need the data*/ - espconn_lock_recv(precv_cb); - - if (p != NULL) { - /*To update and advertise a larger window*/ - if(precv_cb->recv_hold_flag == 0) - tcp_recved(pcb, p->tot_len); - else - precv_cb->recv_holded_buf_Len += p->tot_len; - } - - /*register receive function*/ - if (precv_cb->pespconn->recv_callback != NULL) { - if (err == ERR_OK && p != NULL) { - u8_t *data_ptr = NULL; - u32_t data_cntr = 0; - /*clear the count for connection timeout*/ - precv_cb->pcommon.recv_check = 0; - /*Copy the contents of a packet buffer to an application buffer. - *to prevent memory leaks, ensure that each allocated is deleted*/ - data_ptr = (u8_t *) os_zalloc(p ->tot_len + 1); - data_cntr = pbuf_copy_partial(p, data_ptr, p->tot_len, 0); - pbuf_free(p); - - if (data_cntr != 0) { - /*switch the state of espconn for application process*/ - precv_cb->pespconn->state = ESPCONN_READ; - precv_cb->pcommon.pcb = pcb; - precv_cb->pespconn->recv_callback(precv_cb->pespconn, data_ptr, data_cntr); - - /*switch the state of espconn for next packet copy*/ - if (pcb->state == ESTABLISHED) - precv_cb->pespconn->state = ESPCONN_CONNECT; - } - - /*to prevent memory leaks, ensure that each allocated is deleted*/ - os_free(data_ptr); - data_ptr = NULL; - espconn_printf("server's application data has been processed: %d\n", system_get_free_heap_size()); - } - } else { - /*unregister receive function*/ - struct pbuf *pthis = NULL; - for (pthis = p; pthis != NULL; pthis = pthis->next) { - ringbuf_memcpy_into(precv_cb->readbuf, pthis->payload, pthis->len); - pbuf_free(pthis); - } - } - - if (err == ERR_OK && p == NULL) { - espconn_server_close(precv_cb, pcb, 0); - } - return ERR_OK; -} - -/****************************************************************************** - * FunctionName : espconn_server_sent - * Description : Data has been sent and acknowledged by the remote host. - * This means that more data can be sent. - * Parameters : arg -- Additional argument to pass to the callback function - * pcb -- The connection pcb for which data has been acknowledged - * len -- The amount of bytes acknowledged - * Returns : ERR_OK: try to send some data by calling tcp_output - * ERR_ABRT: if you have called tcp_abort from within the function! -*******************************************************************************/ -static err_t ICACHE_FLASH_ATTR -espconn_server_sent(void *arg, struct tcp_pcb *pcb, u16_t len) -{ - espconn_msg *psent_cb = arg; - - psent_cb->pcommon.pcb = pcb; - psent_cb->pcommon.recv_check = 0; - psent_cb->pcommon.pbuf->tot_len += len; - psent_cb->pcommon.packet_info.sent_length = len; - - /*Send more data for one active connection*/ - espconn_tcp_finish(psent_cb); - return ERR_OK; -} - -/****************************************************************************** - * FunctionName : espconn_server_poll - * Description : The poll function is called every 3nd second. - * If there has been no data sent (which resets the retries) in 3 seconds, close. - * If the last portion of a file has not been sent in 3 seconds, close. - * - * This could be increased, but we don't want to waste resources for bad connections. - * Parameters : arg -- Additional argument to pass to the callback function - * pcb -- The connection pcb for which data has been acknowledged - * Returns : ERR_OK: try to send some data by calling tcp_output - * ERR_ABRT: if you have called tcp_abort from within the function! -*******************************************************************************/ -static err_t ICACHE_FLASH_ATTR -espconn_server_poll(void *arg, struct tcp_pcb *pcb) -{ - espconn_msg *pspoll_cb = arg; - - /*exception calling abandon the connection for send a RST frame*/ - if (arg == NULL) { - tcp_abandon(pcb, 0); - tcp_poll(pcb, NULL, 0); - return ERR_OK; - } - - espconn_printf("espconn_server_poll %d %d\n", pspoll_cb->pcommon.recv_check, pcb->state); - pspoll_cb->pcommon.pcb = pcb; - if (pcb->state == ESTABLISHED) { - pspoll_cb->pcommon.recv_check++; - if (pspoll_cb->pcommon.timeout != 0){/*no data sent in one active connection's set timeout, close.*/ - if (pspoll_cb->pcommon.recv_check >= pspoll_cb->pcommon.timeout) { - pspoll_cb->pcommon.recv_check = 0; - espconn_server_close(pspoll_cb, pcb,0); - } - } else { - espconn_msg *ptime_msg = pserver_list; - while (ptime_msg != NULL) { - if (ptime_msg->pespconn == pspoll_cb->preverse){ - if (ptime_msg->pcommon.timeout != 0){/*no data sent in server's set timeout, close.*/ - if (pspoll_cb->pcommon.recv_check >= ptime_msg->pcommon.timeout){ - pspoll_cb->pcommon.recv_check = 0; - espconn_server_close(pspoll_cb, pcb,0); - } - } else {/*don't close for ever*/ - pspoll_cb->pcommon.recv_check = 0; - } - break; - } - ptime_msg = ptime_msg->pnext; - } - } - } else { - espconn_server_close(pspoll_cb, pcb,0); - } - - return ERR_OK; -} - -/****************************************************************************** - * FunctionName : esponn_server_err - * Description : The pcb had an error and is already deallocated. - * The argument might still be valid (if != NULL). - * Parameters : arg -- Additional argument to pass to the callback function - * err -- Error code to indicate why the pcb has been closed - * Returns : none -*******************************************************************************/ -static void ICACHE_FLASH_ATTR -esponn_server_err(void *arg, err_t err) -{ - espconn_msg *pserr_cb = arg; - struct tcp_pcb *pcb = NULL; - if (pserr_cb != NULL) { - - pcb = pserr_cb->pcommon.pcb; - pserr_cb->pespconn->state = ESPCONN_CLOSE; - -// /*remove the node from the server's active connection list*/ -// espconn_list_delete(&plink_active, pserr_cb); - - /*Set the error code depend on the error type and control block state*/ - if (err == ERR_ABRT) { - switch (pcb->state) { - case SYN_RCVD: - if (pcb->nrtx == TCP_SYNMAXRTX) { - pserr_cb->pcommon.err = ESPCONN_CONN; - } else { - pserr_cb->pcommon.err = err; - } - - break; - - case ESTABLISHED: - if (pcb->nrtx == TCP_MAXRTX) { - pserr_cb->pcommon.err = ESPCONN_TIMEOUT; - } else { - pserr_cb->pcommon.err = err; - } - - break; - - case CLOSE_WAIT: - if (pcb->nrtx == TCP_MAXRTX) { - pserr_cb->pcommon.err = ESPCONN_CLSD; - } else { - pserr_cb->pcommon.err = err; - } - break; - case LAST_ACK: - pserr_cb->pcommon.err = ESPCONN_CLSD; - break; - - case CLOSED: - pserr_cb->pcommon.err = ESPCONN_CONN; - break; - default : - break; - } - } else { - pserr_cb->pcommon.err = err; - } - /*post the singer to the task for processing the connection*/ - ets_post(espconn_TaskPrio, SIG_ESPCONN_ERRER, (uint32_t)pserr_cb); - } -} - -/****************************************************************************** - * FunctionName : espconn_tcp_accept - * Description : A new incoming connection has been accepted. - * Parameters : arg -- Additional argument to pass to the callback function - * pcb -- The connection pcb which is accepted - * err -- An unused error code, always ERR_OK currently - * Returns : acception result -*******************************************************************************/ -static err_t ICACHE_FLASH_ATTR -espconn_tcp_accept(void *arg, struct tcp_pcb *pcb, err_t err) -{ - struct espconn *espconn = arg; - espconn_msg *paccept = NULL; - remot_info *pinfo = NULL; - LWIP_UNUSED_ARG(err); - - if (!espconn || !espconn->proto.tcp) { - return ERR_ARG; - } - - tcp_arg(pcb, paccept); - tcp_err(pcb, esponn_server_err); - /*Ensure the active connection is less than the count of active connections on the server*/ - espconn_get_connection_info(espconn, &pinfo , 0); - espconn_printf("espconn_tcp_accept link_cnt: %d\n", espconn->link_cnt); - if (espconn->link_cnt == espconn_tcp_get_max_con_allow(espconn)) - return ERR_ISCONN; - - /*Creates a new active connect control message*/ - paccept = (espconn_msg *)os_zalloc(sizeof(espconn_msg)); - tcp_arg(pcb, paccept); - - if (paccept == NULL) - return ERR_MEM; - /*Insert the node to the active connection list*/ - espconn_list_creat(&plink_active, paccept); - - paccept->preverse = espconn; - paccept->espconn_mode = ESPCONN_TCPSERVER_MODE; - paccept->pespconn = (struct espconn *)os_zalloc(sizeof(struct espconn)); - if (paccept->pespconn == NULL) - return ERR_MEM; - paccept->pespconn->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); - if (paccept->pespconn->proto.tcp == NULL) - return ERR_MEM; - - /*Reserve the remote information for current active connection*/ - paccept->pcommon.pcb = pcb; - - paccept->pcommon.remote_port = pcb->remote_port; - paccept->pcommon.remote_ip[0] = ip4_addr1_16(&pcb->remote_ip); - paccept->pcommon.remote_ip[1] = ip4_addr2_16(&pcb->remote_ip); - paccept->pcommon.remote_ip[2] = ip4_addr3_16(&pcb->remote_ip); - paccept->pcommon.remote_ip[3] = ip4_addr4_16(&pcb->remote_ip); - paccept->pcommon.write_flag = true; - - os_memcpy(espconn->proto.tcp->remote_ip, paccept->pcommon.remote_ip, 4); - espconn->proto.tcp->remote_port = pcb->remote_port; - espconn->state = ESPCONN_CONNECT; - espconn_copy_partial(paccept->pespconn, espconn); - - /*Set the specify function that should be called - * when TCP data has been successfully delivered, - * when active connection receives data, - * or periodically from active connection*/ - tcp_sent(pcb, espconn_server_sent); - tcp_recv(pcb, espconn_server_recv); - tcp_poll(pcb, espconn_server_poll, 4); /* every 1 seconds */ - /*Disable Nagle algorithm default*/ - tcp_nagle_disable(pcb); - /*Default set the total number of espconn_buf on the unsent lists for one*/ - espconn_tcp_set_buf_count(paccept->pespconn, 1); - - if (paccept->pespconn->proto.tcp->connect_callback != NULL) { - paccept->pespconn->proto.tcp->connect_callback(paccept->pespconn); - } - - /*Enable keep alive option*/ - if (espconn_keepalive_disabled(paccept)) - espconn_keepalive_enable(pcb); - -// /*lock the window because of application layer don't need the data*/ -// espconn_lock_recv(paccept); - return ERR_OK; -} - -/****************************************************************************** - * FunctionName : espconn_tcp_server - * Description : Initialize the server: set up a listening PCB and bind it to - * the defined port - * Parameters : espconn -- the espconn used to build server - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_tcp_server(struct espconn *espconn) -{ - struct tcp_pcb *pcb = NULL; - espconn_msg *pserver = NULL; - - /*Creates a new server control message*/ - pserver = (espconn_msg *)os_zalloc(sizeof(espconn_msg)); - if (pserver == NULL){ - return ESPCONN_MEM; - } - - /*Creates a new TCP protocol control block*/ - pcb = tcp_new(); - if (pcb == NULL) { - /*to prevent memory leaks, ensure that each allocated is deleted*/ - os_free(pserver); - pserver = NULL; - return ESPCONN_MEM; - } else { - struct tcp_pcb *lpcb = NULL; - /*Binds the connection to a local port number and any IP address*/ - tcp_bind(pcb, IP_ADDR_ANY, espconn->proto.tcp->local_port); - lpcb = pcb; - /*malloc and set the state of the connection to be LISTEN*/ - pcb = tcp_listen(pcb); - if (pcb != NULL) { - /*insert the node to the active connection list*/ - espconn_list_creat(&pserver_list, pserver); - pserver->preverse = pcb; - pserver->pespconn = espconn; - pserver->count_opt = MEMP_NUM_TCP_PCB; - pserver->pcommon.timeout = 0x0a; - espconn ->state = ESPCONN_LISTEN; - /*set the specify argument that should be passed callback function*/ - tcp_arg(pcb, (void *)espconn); - /*accept callback function to call for this control block*/ - tcp_accept(pcb, espconn_tcp_accept); - return ESPCONN_OK; - } else { - /*to prevent memory leaks, ensure that each allocated is deleted*/ - memp_free(MEMP_TCP_PCB,lpcb); - os_free(pserver); - pserver = NULL; - return ESPCONN_MEM; - } - } -} - -/****************************************************************************** - * FunctionName : espconn_tcp_delete - * Description : delete the server: delete a listening PCB and free it - * Parameters : pdeletecon -- the espconn used to delete a server - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR espconn_tcp_delete(struct espconn *pdeletecon) -{ - err_t err; - remot_info *pinfo = NULL; - espconn_msg *pdelete_msg = NULL; - struct tcp_pcb *pcb = NULL; - - if (pdeletecon == NULL) - return ESPCONN_ARG; - - espconn_get_connection_info(pdeletecon, &pinfo , 0); - /*make sure all the active connection have been disconnect*/ - if (pdeletecon->link_cnt != 0) - return ESPCONN_INPROGRESS; - else { - espconn_printf("espconn_tcp_delete %p\n",pdeletecon); - pdelete_msg = pserver_list; - while (pdelete_msg != NULL){ - if (pdelete_msg->pespconn == pdeletecon){ - /*remove the node from the client's active connection list*/ - espconn_list_delete(&pserver_list, pdelete_msg); - pcb = pdelete_msg->preverse; - os_printf("espconn_tcp_delete %d, %d\n",pcb->state, pcb->local_port); - espconn_kill_pcb(pcb->local_port); - err = tcp_close(pcb); - os_free(pdelete_msg); - pdelete_msg = NULL; - break; - } - pdelete_msg = pdelete_msg->pnext; - } - if (err == ERR_OK) - return err; - else - return ESPCONN_ARG; - } -} - -/****************************************************************************** - * FunctionName : espconn_init - * Description : used to init the function that should be used when - * Parameters : none - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR espconn_init(void) -{ - ets_task(espconn_Task, espconn_TaskPrio, espconn_TaskQueue, espconn_TaskQueueLen); -} diff --git a/tools/sdk/lwip/src/app/espconn_udp.c b/tools/sdk/lwip/src/app/espconn_udp.c deleted file mode 100644 index e3ac8e60f..000000000 --- a/tools/sdk/lwip/src/app/espconn_udp.c +++ /dev/null @@ -1,424 +0,0 @@ -/****************************************************************************** - * Copyright 2013-2014 Espressif Systems (Wuxi) - * - * FileName: espconn_udp.c - * - * Description: udp proto interface - * - * Modification history: - * 2014/3/31, v1.0 create this file. -*******************************************************************************/ - -#include "ets_sys.h" -#include "os_type.h" -//#include "os.h" - -#include "lwip/inet.h" -#include "lwip/err.h" -#include "lwip/pbuf.h" -#include "lwip/mem.h" -#include "lwip/tcp_impl.h" -#include "lwip/udp.h" - -#include "lwip/app/espconn_udp.h" - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -extern espconn_msg *plink_active; -extern uint8 default_interface; - -enum send_opt{ - ESPCONN_SENDTO, - ESPCONN_SEND -}; -static void ICACHE_FLASH_ATTR espconn_data_sentcb(struct espconn *pespconn) -{ - if (pespconn == NULL) { - return; - } - - if (pespconn->sent_callback != NULL) { - pespconn->sent_callback(pespconn); - } -} - -static void ICACHE_FLASH_ATTR espconn_data_sent(void *arg, enum send_opt opt) -{ - espconn_msg *psent = arg; - - if (psent == NULL) { - return; - } - - if (psent->pcommon.cntr == 0) { - psent->pespconn->state = ESPCONN_CONNECT; - if (psent->pcommon.err == 0) - espconn_data_sentcb(psent->pespconn); - } else { - if (opt == ESPCONN_SEND){ - espconn_udp_sent(arg, psent->pcommon.ptrbuf, psent->pcommon.cntr); - } else { - espconn_udp_sendto(arg, psent->pcommon.ptrbuf, psent->pcommon.cntr); - } - } -} - -/****************************************************************************** - * FunctionName : espconn_udp_sent - * Description : sent data for client or server - * Parameters : void *arg -- client or server to send - * uint8* psent -- Data to send - * uint16 length -- Length of data to send - * Returns : return espconn error code. - * - ESPCONN_OK. Successful. No error occured. - * - ESPCONN_MEM. Out of memory. - * - ESPCONN_RTE. Could not find route to destination address. - * - More errors could be returned by lower protocol layers. -*******************************************************************************/ -err_t ICACHE_FLASH_ATTR -espconn_udp_sent(void *arg, uint8 *psent, uint16 length) -{ - espconn_msg *pudp_sent = arg; - struct udp_pcb *upcb = pudp_sent->pcommon.pcb; - struct pbuf *p, *q ,*p_temp; - u8_t *data = NULL; - u16_t cnt = 0; - u16_t datalen = 0; - u16_t i = 0; - err_t err; - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d %p\n", __LINE__, length, upcb)); - - if (pudp_sent == NULL || upcb == NULL || psent == NULL || length == 0) { - return ESPCONN_ARG; - } - - if ((IP_FRAG_MAX_MTU - 20 - 8) < length) { - datalen = IP_FRAG_MAX_MTU - 20 - 8; - } else { - datalen = length; - } - - p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p)); - - if (p != NULL) { - q = p; - - while (q != NULL) { - data = (u8_t *)q->payload; - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, data)); - - for (i = 0; i < q->len; i++) { - data[i] = ((u8_t *) psent)[cnt++]; - } - - q = q->next; - } - } else { - return ESPCONN_MEM; - } - - upcb->remote_port = pudp_sent->pespconn->proto.udp->remote_port; - IP4_ADDR(&upcb->remote_ip, pudp_sent->pespconn->proto.udp->remote_ip[0], - pudp_sent->pespconn->proto.udp->remote_ip[1], - pudp_sent->pespconn->proto.udp->remote_ip[2], - pudp_sent->pespconn->proto.udp->remote_ip[3]); - - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %x %d\n", __LINE__, upcb->remote_ip, upcb->remote_port)); - - struct netif *sta_netif = (struct netif *)eagle_lwip_getif(0x00); - struct netif *ap_netif = (struct netif *)eagle_lwip_getif(0x01); - - if(wifi_get_opmode() == ESPCONN_AP_STA && default_interface == ESPCONN_AP_STA && sta_netif != NULL && ap_netif != NULL) - { - if(netif_is_up(sta_netif) && netif_is_up(ap_netif) && \ - ip_addr_isbroadcast(&upcb->remote_ip, sta_netif) && \ - ip_addr_isbroadcast(&upcb->remote_ip, ap_netif)) { - - p_temp = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); - if (pbuf_copy (p_temp,p) != ERR_OK) { - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent: copying to new pbuf failed\n")); - return ESPCONN_ARG; - } - netif_set_default(sta_netif); - err = udp_send(upcb, p_temp); - pbuf_free(p_temp); - netif_set_default(ap_netif); - } - } - err = udp_send(upcb, p); - - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d\n", __LINE__, err)); - - if (p->ref != 0) { - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p)); - pbuf_free(p); - pudp_sent->pcommon.ptrbuf = psent + datalen; - pudp_sent->pcommon.cntr = length - datalen; - pudp_sent->pcommon.err = err; - espconn_data_sent(pudp_sent, ESPCONN_SEND); - if (err > 0) - return ESPCONN_IF; - return err; - } else { - pbuf_free(p); - return ESPCONN_RTE; - } -} - -/****************************************************************************** - * FunctionName : espconn_udp_sendto - * Description : sent data for UDP - * Parameters : void *arg -- UDP to send - * uint8* psent -- Data to send - * uint16 length -- Length of data to send - * Returns : return espconn error code. - * - ESPCONN_OK. Successful. No error occured. - * - ESPCONN_MEM. Out of memory. - * - ESPCONN_RTE. Could not find route to destination address. - * - More errors could be returned by lower protocol layers. -*******************************************************************************/ -err_t ICACHE_FLASH_ATTR -espconn_udp_sendto(void *arg, uint8 *psent, uint16 length) -{ - espconn_msg *pudp_sent = arg; - struct udp_pcb *upcb = pudp_sent->pcommon.pcb; - struct espconn *pespconn = pudp_sent->pespconn; - struct pbuf *p, *q ,*p_temp; - struct ip_addr dst_ip; - u16_t dst_port; - u8_t *data = NULL; - u16_t cnt = 0; - u16_t datalen = 0; - u16_t i = 0; - err_t err; - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d %p\n", __LINE__, length, upcb)); - - if (pudp_sent == NULL || upcb == NULL || psent == NULL || length == 0) { - return ESPCONN_ARG; - } - - if ((IP_FRAG_MAX_MTU - 20 - 8) < length) { - datalen = IP_FRAG_MAX_MTU - 20 - 8; - } else { - datalen = length; - } - - p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p)); - - if (p != NULL) { - q = p; - - while (q != NULL) { - data = (u8_t *)q->payload; - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, data)); - - for (i = 0; i < q->len; i++) { - data[i] = ((u8_t *) psent)[cnt++]; - } - - q = q->next; - } - } else { - return ESPCONN_MEM; - } - - dst_port = pespconn->proto.udp->remote_port; - IP4_ADDR(&dst_ip, pespconn->proto.udp->remote_ip[0], - pespconn->proto.udp->remote_ip[1], pespconn->proto.udp->remote_ip[2], - pespconn->proto.udp->remote_ip[3]); - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %x %d\n", __LINE__, upcb->remote_ip, upcb->remote_port)); - - struct netif *sta_netif = (struct netif *)eagle_lwip_getif(0x00); - struct netif *ap_netif = (struct netif *)eagle_lwip_getif(0x01); - - if(wifi_get_opmode() == ESPCONN_AP_STA && default_interface == ESPCONN_AP_STA && sta_netif != NULL && ap_netif != NULL) - { - if(netif_is_up(sta_netif) && netif_is_up(ap_netif) && \ - ip_addr_isbroadcast(&upcb->remote_ip, sta_netif) && \ - ip_addr_isbroadcast(&upcb->remote_ip, ap_netif)) { - - p_temp = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); - if (pbuf_copy (p_temp,p) != ERR_OK) { - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sendto: copying to new pbuf failed\n")); - return ESPCONN_ARG; - } - netif_set_default(sta_netif); - err = udp_sendto(upcb, p_temp, &dst_ip, dst_port); - pbuf_free(p_temp); - netif_set_default(ap_netif); - } - } - err = udp_sendto(upcb, p, &dst_ip, dst_port); - - if (p->ref != 0) { - pbuf_free(p); - pudp_sent->pcommon.ptrbuf = psent + datalen; - pudp_sent->pcommon.cntr = length - datalen; - pudp_sent->pcommon.err = err; - espconn_data_sent(pudp_sent, ESPCONN_SENDTO); - - if (err > 0) - return ESPCONN_IF; - return err; - } else { - pbuf_free(p); - return ESPCONN_RTE; - } -} - -/****************************************************************************** - * FunctionName : espconn_udp_server_recv - * Description : This callback will be called when receiving a datagram. - * Parameters : arg -- user supplied argument - * upcb -- the udp_pcb which received data - * p -- the packet buffer that was received - * addr -- the remote IP address from which the packet was received - * port -- the remote port from which the packet was received - * Returns : none -*******************************************************************************/ -static void ICACHE_FLASH_ATTR -espconn_udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, - struct ip_addr *addr, u16_t port) -{ - espconn_msg *precv = arg; - struct pbuf *q = NULL; - u8_t *pdata = NULL; - u16_t length = 0; - struct ip_info ipconfig; - - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_server_recv %d %p\n", __LINE__, upcb)); - - precv->pcommon.remote_ip[0] = ip4_addr1_16(addr); - precv->pcommon.remote_ip[1] = ip4_addr2_16(addr); - precv->pcommon.remote_ip[2] = ip4_addr3_16(addr); - precv->pcommon.remote_ip[3] = ip4_addr4_16(addr); - precv->pcommon.remote_port = port; - precv->pcommon.pcb = upcb; - - if (wifi_get_opmode() != 1) { - wifi_get_ip_info(1, &ipconfig); - - if (!ip_addr_netcmp(addr, &ipconfig.ip, &ipconfig.netmask)) { - wifi_get_ip_info(0, &ipconfig); - } - } else { - wifi_get_ip_info(0, &ipconfig); - } - - precv->pespconn->proto.udp->local_ip[0] = ip4_addr1_16(&ipconfig.ip); - precv->pespconn->proto.udp->local_ip[1] = ip4_addr2_16(&ipconfig.ip); - precv->pespconn->proto.udp->local_ip[2] = ip4_addr3_16(&ipconfig.ip); - precv->pespconn->proto.udp->local_ip[3] = ip4_addr4_16(&ipconfig.ip); - - if (p != NULL) { - pdata = (u8_t *)os_zalloc(p ->tot_len + 1); - length = pbuf_copy_partial(p, pdata, p ->tot_len, 0); - precv->pcommon.pcb = upcb; - pbuf_free(p); - if (length != 0) { - if (precv->pespconn->recv_callback != NULL) { - precv->pespconn->recv_callback(precv->pespconn, pdata, length); - } - } - os_free(pdata); - } else { - return; - } -} - -/****************************************************************************** - * FunctionName : espconn_udp_disconnect - * Description : A new incoming connection has been disconnected. - * Parameters : espconn -- the espconn used to disconnect with host - * Returns : none -*******************************************************************************/ -void ICACHE_FLASH_ATTR espconn_udp_disconnect(espconn_msg *pdiscon) -{ - if (pdiscon == NULL) { - return; - } - - struct udp_pcb *upcb = pdiscon->pcommon.pcb; - - udp_disconnect(upcb); - - udp_remove(upcb); - - espconn_list_delete(&plink_active, pdiscon); - - os_free(pdiscon); - pdiscon = NULL; -} - -/****************************************************************************** - * FunctionName : espconn_udp_server - * Description : Initialize the server: set up a PCB and bind it to the port - * Parameters : pespconn -- the espconn used to build server - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_udp_server(struct espconn *pespconn) -{ - struct udp_pcb *upcb = NULL; - espconn_msg *pserver = NULL; - upcb = udp_new(); - - if (upcb == NULL) { - return ESPCONN_MEM; - } else { - pserver = (espconn_msg *)os_zalloc(sizeof(espconn_msg)); - - if (pserver == NULL) { - udp_remove(upcb); - return ESPCONN_MEM; - } - - pserver->pcommon.pcb = upcb; - pserver->pespconn = pespconn; - espconn_list_creat(&plink_active, pserver); - udp_bind(upcb, IP_ADDR_ANY, pserver->pespconn->proto.udp->local_port); - udp_recv(upcb, espconn_udp_recv, (void *)pserver); - return ESPCONN_OK; - } -} - -/****************************************************************************** - * FunctionName : espconn_igmp_leave - * Description : leave a multicast group - * Parameters : host_ip -- the ip address of udp server - * multicast_ip -- multicast ip given by user - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip) -{ - if (igmp_leavegroup(host_ip, multicast_ip) != ERR_OK) { - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("udp_leave_multigrup failed!\n")); - return -1; - }; - - return ESPCONN_OK; -} - -/****************************************************************************** - * FunctionName : espconn_igmp_join - * Description : join a multicast group - * Parameters : host_ip -- the ip address of udp server - * multicast_ip -- multicast ip given by user - * Returns : none -*******************************************************************************/ -sint8 ICACHE_FLASH_ATTR -espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip) -{ - if (igmp_joingroup(host_ip, multicast_ip) != ERR_OK) { - LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("udp_join_multigrup failed!\n")); - return -1; - }; - - /* join to any IP address at the port */ - return ESPCONN_OK; -} diff --git a/tools/sdk/lwip/src/app/netio.c b/tools/sdk/lwip/src/app/netio.c deleted file mode 100644 index 47b359934..000000000 --- a/tools/sdk/lwip/src/app/netio.c +++ /dev/null @@ -1,369 +0,0 @@ -/** - * @file - * MetIO Server - * - */ - -/* - * 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/opt.h" - -#if LWIP_TCP -#include "lwip/tcp.h" - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -/* - * This implements a netio server. - * The client sends a command word (4 bytes) then a data length word (4 bytes). - * If the command is "receive", the server is to consume "data length" bytes into - * a circular buffer until the first byte is non-zero, then it is to consume - * another command/data pair. - * If the command is "send", the server is to send "data length" bytes from a circular - * buffer with the first byte being zero, until "some time" (6 seconds in the - * current netio126.zip download) has passed and then send one final buffer with - * the first byte being non-zero. Then it is to consume another command/data pair. - */ - -/* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */ - -/* implementation options */ -#define NETIO_BUF_SIZE (4 * 1024) -#define NETIO_USE_STATIC_BUF 0 - -/* NetIO server state definition */ -#define NETIO_STATE_WAIT_FOR_CMD 0 -#define NETIO_STATE_RECV_DATA 1 -#define NETIO_STATE_SEND_DATA 2 -#define NETIO_STATE_SEND_DATA_LAST 3 -#define NETIO_STATE_DONE 4 - -struct netio_state { - u32_t state; - u32_t cmd; - u32_t data_len; - u32_t cntr; - u8_t * buf_ptr; - u32_t buf_pos; - u32_t first_byte; - u32_t time_stamp; -}; - -/* NetIO command protocol definition */ -#define NETIO_CMD_QUIT 0 -#define NETIO_CMD_C2S 1 -#define NETIO_CMD_S2C 2 -#define NETIO_CMD_RES 3 - -static err_t netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); - -static void ICACHE_FLASH_ATTR -netio_close(void *arg, struct tcp_pcb *pcb) -{ - err_t err; - - struct netio_state *ns = arg; - ns->state = NETIO_STATE_DONE; - tcp_recv(pcb, NULL); - err = tcp_close(pcb); - - if (err != ERR_OK) { - /* closing failed, try again later */ - tcp_recv(pcb, netio_recv); - } else { - /* closing succeeded */ -#if NETIO_USE_STATIC_BUF != 1 - if(ns->buf_ptr != NULL){ - mem_free(ns->buf_ptr); - } -#endif - tcp_arg(pcb, NULL); - tcp_poll(pcb, NULL, 0); - tcp_sent(pcb, NULL); - if (arg != NULL) { - mem_free(arg); - } - } -} - -static err_t ICACHE_FLASH_ATTR -netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) -{ - struct netio_state *ns = arg; - u8_t * data_ptr; - u32_t data_cntr; - struct pbuf *q = p; - u16_t len; - - if (p != NULL) { - tcp_recved(pcb, p->tot_len); - } - - if (err == ERR_OK && q != NULL) { - - while (q != NULL) { - data_cntr = q->len; - data_ptr = q->payload; - while (data_cntr--) { - if (ns->state == NETIO_STATE_DONE){ - netio_close(ns, pcb); - break; - } else if (ns->state == NETIO_STATE_WAIT_FOR_CMD) { - if (ns->cntr < 4) { - /* build up the CMD field */ - ns->cmd <<= 8; - ns->cmd |= *data_ptr++; - ns->cntr++; - } else if (ns->cntr < 8) { - /* build up the DATA field */ - ns->data_len <<= 8; - ns->data_len |= *data_ptr++; - ns->cntr++; - - if (ns->cntr == 8) { - /* now we have full command and data words */ - ns->cntr = 0; - ns->buf_pos = 0; - ns->buf_ptr[0] = 0; - if (ns->cmd == NETIO_CMD_C2S) { - ns->state = NETIO_STATE_RECV_DATA; - } else if (ns->cmd == NETIO_CMD_S2C) { - ns->state = NETIO_STATE_SEND_DATA; - /* start timer */ - ns->time_stamp = sys_now(); - /* send first round of data */ - - len = tcp_sndbuf(pcb); - len = LWIP_MIN(len, ns->data_len - ns->cntr); - len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos); - - do { - err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY); - if (err == ERR_MEM) { - len /= 2; - } - } while ((err == ERR_MEM) && (len > 1)); - - ns->buf_pos += len; - ns->cntr += len; - - } else { - /* unrecognized command, punt */ - ns->cntr = 0; - ns->buf_pos = 0; - ns->buf_ptr[0] = 0; - netio_close(ns, pcb); - break; - } - } - } else { - /* in trouble... shouldn't be in this state! */ - } - - } else if (ns->state == NETIO_STATE_RECV_DATA) { - - if(ns->cntr == 0){ - /* save the first byte of this new round of data - * this will not match ns->buf_ptr[0] in the case that - * NETIO_BUF_SIZE is less than ns->data_len. - */ - ns->first_byte = *data_ptr; - } - - ns->buf_ptr[ns->buf_pos++] = *data_ptr++; - ns->cntr++; - - if (ns->buf_pos == NETIO_BUF_SIZE) { - /* circularize the buffer */ - ns->buf_pos = 0; - } - - if(ns->cntr == ns->data_len){ - ns->cntr = 0; - if (ns->first_byte != 0) { - /* if this last round did not start with 0, - * go look for another command */ - ns->state = NETIO_STATE_WAIT_FOR_CMD; - ns->data_len = 0; - ns->cmd = 0; - /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */ - } else { - /* stay here and wait on more data */ - } - } - - } else if (ns->state == NETIO_STATE_SEND_DATA - || ns->state == NETIO_STATE_SEND_DATA_LAST) { - /* I don't think this should happen... */ - } else { - /* done / quit */ - netio_close(ns, pcb); - break; - } /* end of ns->state condition */ - } /* end of while data still in this pbuf */ - - q = q->next; - } - - pbuf_free(p); - - } else { - - /* error or closed by other side */ - if (p != NULL) { - pbuf_free(p); - } - - /* close the connection */ - netio_close(ns, pcb); - - } - return ERR_OK; - -} - -static err_t ICACHE_FLASH_ATTR -netio_sent(void *arg, struct tcp_pcb *pcb, u16_t len) -{ - struct netio_state *ns = arg; - err_t err = ERR_OK; - - if (ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA) { - /* done with this round of sending */ - ns->buf_pos = 0; - ns->cntr = 0; - - /* check if timer expired */ - if (sys_now() - ns->time_stamp > 600) { - ns->buf_ptr[0] = 1; - ns->state = NETIO_STATE_SEND_DATA_LAST; - } else { - ns->buf_ptr[0] = 0; - } - } - - if(ns->state == NETIO_STATE_SEND_DATA_LAST || ns->state == NETIO_STATE_SEND_DATA){ - len = tcp_sndbuf(pcb); - len = LWIP_MIN(len, ns->data_len - ns->cntr); - len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos); - - if(ns->cntr < ns->data_len){ - do { - err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY); - if (err == ERR_MEM) { - len /= 2; - } - } while ((err == ERR_MEM) && (len > 1)); - - ns->buf_pos += len; - if(ns->buf_pos >= NETIO_BUF_SIZE){ - ns->buf_pos = 0; - } - - ns->cntr += len; - } - } - - if(ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA_LAST){ - /* we have buffered up all our data to send this last round, go look for a command */ - ns->state = NETIO_STATE_WAIT_FOR_CMD; - ns->cntr = 0; - /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */ - } - - return ERR_OK; -} - -static err_t ICACHE_FLASH_ATTR -netio_poll(void *arg, struct tcp_pcb *pcb) -{ - struct netio_state * ns = arg; - if(ns->state == NETIO_STATE_SEND_DATA){ - - } else if(ns->state == NETIO_STATE_DONE){ - netio_close(ns, pcb); - } - - return ERR_OK; - -} - -#if NETIO_USE_STATIC_BUF == 1 -static u8_t netio_buf[NETIO_BUF_SIZE]; -#endif - -static err_t ICACHE_FLASH_ATTR -netio_accept(void *arg, struct tcp_pcb *pcb, err_t err) -{ - struct netio_state * ns; - - LWIP_UNUSED_ARG(err); - - ns = (struct netio_state *)mem_malloc(sizeof(struct netio_state)); - - if(ns == NULL){ - return ERR_MEM; - } - - ns->state = NETIO_STATE_WAIT_FOR_CMD; - ns->data_len = 0; - ns->cmd = 0; - ns->cntr = 0; - ns->buf_pos = 0; -#if NETIO_USE_STATIC_BUF == 1 - ns->buf_ptr = netio_buf; -#else - ns->buf_ptr = (u8_t *)mem_malloc(NETIO_BUF_SIZE); - - if(ns->buf_ptr == NULL){ - mem_free(ns); - return ERR_MEM; - } -#endif - - ns->buf_ptr[0] = 0; - - tcp_arg(pcb, ns); - tcp_sent(pcb, netio_sent); - tcp_recv(pcb, netio_recv); - tcp_poll(pcb, netio_poll, 4); /* every 2 seconds */ - return ERR_OK; -} - -void ICACHE_FLASH_ATTR netio_init(void) -{ - struct tcp_pcb *pcb; - - pcb = tcp_new(); - tcp_bind(pcb, IP_ADDR_ANY, 18767); - pcb = tcp_listen(pcb); - tcp_accept(pcb, netio_accept); -} - -#endif /* LWIP_TCP */ diff --git a/tools/sdk/lwip/src/app/ping.c b/tools/sdk/lwip/src/app/ping.c deleted file mode 100644 index 6bd6f0ea0..000000000 --- a/tools/sdk/lwip/src/app/ping.c +++ /dev/null @@ -1,329 +0,0 @@ -/** - * @file - * Ping sender module - * - */ - -/* - * 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. - * - */ - -/** - * This is an example of a "ping" sender (with raw API and socket API). - * It can be used as a start point to maintain opened a network connection, or - * like a network "watchdog" for your device. - * - */ - -/* - * copyright (c) 2010 - 2011 Espressif System - */ - -#include "lwip/opt.h" - -#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/mem.h" -#include "lwip/raw.h" -#include "lwip/icmp.h" -#include "lwip/netif.h" -#include "lwip/sys.h" -#include "lwip/timers.h" -#include "lwip/inet_chksum.h" -#include "os_type.h" -#include "osapi.h" - -#include "lwip/app/ping.h" - -#if PING_USE_SOCKETS -#include "lwip/sockets.h" -#include "lwip/inet.h" -#endif /* PING_USE_SOCKETS */ - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -/* ping variables */ -static u16_t ping_seq_num = 0; -static u32_t ping_time; - -static void ICACHE_FLASH_ATTR ping_timeout(void* arg) -{ - struct ping_msg *pingmsg = (struct ping_msg *)arg; - pingmsg->timeout_count ++; - if (pingmsg->ping_opt->recv_function == NULL){ - os_printf("ping timeout\n"); - } else { - struct ping_resp pingresp; - os_bzero(&pingresp, sizeof(struct ping_resp)); - pingresp.ping_err = -1; - pingmsg->ping_opt->recv_function(pingmsg->ping_opt, (void*)&pingresp); - } -} - -/** Prepare a echo ICMP request */ -static void ICACHE_FLASH_ATTR -ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len) -{ - size_t i = 0; - size_t data_len = len - sizeof(struct icmp_echo_hdr); - - ICMPH_TYPE_SET(iecho, ICMP_ECHO); - ICMPH_CODE_SET(iecho, 0); - iecho->chksum = 0; - iecho->id = PING_ID; - ++ ping_seq_num; - if (ping_seq_num == 0x7fff) - ping_seq_num = 0; - - iecho->seqno = htons(ping_seq_num); - - /* fill the additional data buffer with some data */ - for(i = 0; i < data_len; i++) { - ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; - } - - iecho->chksum = inet_chksum(iecho, len); -} - -static void ICACHE_FLASH_ATTR -ping_prepare_er(struct icmp_echo_hdr *iecho, u16_t len) -{ - - ICMPH_TYPE_SET(iecho, ICMP_ER); - ICMPH_CODE_SET(iecho, 0); - iecho->chksum = 0; - - iecho->chksum = inet_chksum(iecho, len); -} - -/* Ping using the raw ip */ -static u8_t ICACHE_FLASH_ATTR -ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) -{ - struct icmp_echo_hdr *iecho = NULL; - static u16_t seqno = 0; - struct ping_msg *pingmsg = (struct ping_msg*)arg; - - LWIP_UNUSED_ARG(arg); - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(addr); - LWIP_ASSERT("p != NULL", p != NULL); - - if (pbuf_header( p, -PBUF_IP_HLEN)==0) { - iecho = (struct icmp_echo_hdr *)p->payload; - - if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)) && iecho->type == ICMP_ER) { - LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); - ip_addr_debug_print(PING_DEBUG, addr); - LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now()-ping_time))); - if (iecho->seqno != seqno){ - /* do some ping result processing */ - { - struct ip_hdr *iphdr = NULL; - char ipaddrstr[16]; - ip_addr_t source_ip; - sys_untimeout(ping_timeout, pingmsg); - os_bzero(&source_ip, sizeof(ip_addr_t)); - os_bzero(ipaddrstr, sizeof(ipaddrstr)); - uint32 delay = system_relative_time(pingmsg->ping_sent); - delay /= PING_COARSE; - iphdr = (struct ip_hdr*)((u8*)iecho - PBUF_IP_HLEN); - source_ip.addr = iphdr->src.addr; - ipaddr_ntoa_r(&source_ip,ipaddrstr, sizeof(ipaddrstr)); - if (pingmsg->ping_opt->recv_function == NULL){ - os_printf("recv %s: byte = %d, time = %d ms, seq = %d\n",ipaddrstr, PING_DATA_SIZE, delay, ntohs(iecho->seqno)); - } else { - struct ping_resp pingresp; - os_bzero(&pingresp, sizeof(struct ping_resp)); - pingresp.bytes = PING_DATA_SIZE; - pingresp.resp_time = delay; - pingresp.seqno = ntohs(iecho->seqno); - pingresp.ping_err = 0; - pingmsg->ping_opt->recv_function(pingmsg->ping_opt,(void*) &pingresp); - } - } - seqno = iecho->seqno; - } - - PING_RESULT(1); - pbuf_free(p); - return 1; /* eat the packet */ - } -// } else if(iecho->type == ICMP_ECHO){ -// struct pbuf *q = NULL; -// os_printf("receive ping request:seq=%d\n", ntohs(iecho->seqno)); -// q = pbuf_alloc(PBUF_IP, (u16_t)p->tot_len, PBUF_RAM); -// if (q!=NULL) { -// pbuf_copy(q, p); -// iecho = (struct icmp_echo_hdr *)q->payload; -// ping_prepare_er(iecho, q->tot_len); -// raw_sendto(pcb, q, addr); -// pbuf_free(q); -// } -// pbuf_free(p); -// return 1; -// } - } - - return 0; /* don't eat the packet */ -} - -static void ICACHE_FLASH_ATTR -ping_send(struct raw_pcb *raw, ip_addr_t *addr) -{ - struct pbuf *p = NULL; - struct icmp_echo_hdr *iecho = NULL; - size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; - - LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); - ip_addr_debug_print(PING_DEBUG, addr); - LWIP_DEBUGF( PING_DEBUG, ("\n")); - LWIP_ASSERT("ping_size <= 0xffff", ping_size <= 0xffff); - - p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM); - if (!p) { - return; - } - if ((p->len == p->tot_len) && (p->next == NULL)) { - iecho = (struct icmp_echo_hdr *)p->payload; - - ping_prepare_echo(iecho, (u16_t)ping_size); - - raw_sendto(raw, p, addr); - ping_time = sys_now(); - } - pbuf_free(p); -} - -static void ICACHE_FLASH_ATTR -ping_coarse_tmr(void *arg) -{ - struct ping_msg *pingmsg = (struct ping_msg*)arg; - struct ping_option *ping_opt= NULL; - struct ping_resp pingresp; - ip_addr_t ping_target; - - LWIP_ASSERT("ping_timeout: no pcb given!", pingmsg != NULL); - ping_target.addr = pingmsg->ping_opt->ip; - ping_opt = pingmsg->ping_opt; - if (--pingmsg->sent_count != 0){ - pingmsg ->ping_sent = system_get_time(); - ping_send(pingmsg->ping_pcb, &ping_target); - - sys_timeout(PING_TIMEOUT_MS, ping_timeout, pingmsg); - sys_timeout(pingmsg->coarse_time, ping_coarse_tmr, pingmsg); - } else { - uint32 delay = system_relative_time(pingmsg->ping_start); - delay /= PING_COARSE; -// ping_seq_num = 0; - if (ping_opt->sent_function == NULL){ - os_printf("ping %d, timeout %d, total payload %d bytes, %d ms\n", - pingmsg->max_count, pingmsg->timeout_count, PING_DATA_SIZE*(pingmsg->max_count - pingmsg->timeout_count),delay); - } else { - os_bzero(&pingresp, sizeof(struct ping_resp)); - pingresp.total_count = pingmsg->max_count; - pingresp.timeout_count = pingmsg->timeout_count; - pingresp.total_bytes = PING_DATA_SIZE*(pingmsg->max_count - pingmsg->timeout_count); - pingresp.total_time = delay; - pingresp.ping_err = 0; - } - sys_untimeout(ping_coarse_tmr, pingmsg); - raw_remove(pingmsg->ping_pcb); - os_free(pingmsg); - if (ping_opt->sent_function != NULL) - ping_opt->sent_function(ping_opt,(uint8*)&pingresp); - } -} - -static bool ICACHE_FLASH_ATTR -ping_raw_init(struct ping_msg *pingmsg) -{ - if (pingmsg == NULL) - return false; - - ip_addr_t ping_target; - pingmsg->ping_pcb = raw_new(IP_PROTO_ICMP); - LWIP_ASSERT("ping_pcb != NULL", pingmsg->ping_pcb != NULL); - - raw_recv(pingmsg->ping_pcb, ping_recv, pingmsg); - raw_bind(pingmsg->ping_pcb, IP_ADDR_ANY); - - ping_target.addr = pingmsg->ping_opt->ip; - pingmsg ->ping_sent = system_get_time(); - ping_send(pingmsg->ping_pcb, &ping_target); - - sys_timeout(PING_TIMEOUT_MS, ping_timeout, pingmsg); - sys_timeout(pingmsg->coarse_time, ping_coarse_tmr, pingmsg); - return true; -} - -bool ICACHE_FLASH_ATTR -ping_start(struct ping_option *ping_opt) -{ - struct ping_msg *pingmsg = NULL; - pingmsg = (struct ping_msg *)os_zalloc(sizeof(struct ping_msg)); - if (pingmsg == NULL || ping_opt == NULL) - return false; - - pingmsg->ping_opt = ping_opt; - if (ping_opt->count != 0) - pingmsg->max_count = ping_opt->count; - else - pingmsg->max_count = DEFAULT_PING_MAX_COUNT; - - if (ping_opt->coarse_time != 0) - pingmsg->coarse_time = ping_opt->coarse_time * PING_COARSE; - else - pingmsg->coarse_time = PING_COARSE; - - pingmsg->ping_start = system_get_time(); - pingmsg->sent_count = pingmsg->max_count; - return ping_raw_init(pingmsg); -} - -bool ICACHE_FLASH_ATTR -ping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv) -{ - if (ping_opt == NULL) - return false; - - ping_opt ->recv_function = ping_recv; - return true; -} - -bool ICACHE_FLASH_ATTR -ping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent) -{ - if (ping_opt == NULL) - return false; - - ping_opt ->sent_function = ping_sent; - return true; -} - -#endif /* LWIP_RAW */ diff --git a/tools/sdk/lwip/src/core/def.c b/tools/sdk/lwip/src/core/def.c deleted file mode 100644 index 352b55241..000000000 --- a/tools/sdk/lwip/src/core/def.c +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @file - * Common functions used throughout the stack. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ - -#include "lwip/opt.h" -#include "lwip/def.h" - -/** - * These are reference implementations of the byte swapping functions. - * Again with the aim of being simple, correct and fully portable. - * Byte swapping is the second thing you would want to optimize. You will - * need to port it to your architecture and in your cc.h: - * - * #define LWIP_PLATFORM_BYTESWAP 1 - * #define LWIP_PLATFORM_HTONS(x) - * #define LWIP_PLATFORM_HTONL(x) - * - * Note ntohs() and ntohl() are merely references to the htonx counterparts. - */ - -#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) - -/** - * Convert an u16_t from host- to network byte order. - * - * @param n u16_t in host byte order - * @return n in network byte order - */ -u16_t -lwip_htons(u16_t n) -{ - return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); -} - -/** - * Convert an u16_t from network- to host byte order. - * - * @param n u16_t in network byte order - * @return n in host byte order - */ -u16_t -lwip_ntohs(u16_t n) -{ - return lwip_htons(n); -} - -/** - * Convert an u32_t from host- to network byte order. - * - * @param n u32_t in host byte order - * @return n in network byte order - */ -u32_t -lwip_htonl(u32_t n) -{ - return ((n & 0xff) << 24) | - ((n & 0xff00) << 8) | - ((n & 0xff0000UL) >> 8) | - ((n & 0xff000000UL) >> 24); -} - -/** - * Convert an u32_t from network- to host byte order. - * - * @param n u32_t in network byte order - * @return n in host byte order - */ -u32_t -lwip_ntohl(u32_t n) -{ - return lwip_htonl(n); -} - -#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */ diff --git a/tools/sdk/lwip/src/core/dhcp.c b/tools/sdk/lwip/src/core/dhcp.c deleted file mode 100755 index 17b2a47e1..000000000 --- a/tools/sdk/lwip/src/core/dhcp.c +++ /dev/null @@ -1,1815 +0,0 @@ -/** - * @file - * Dynamic Host Configuration Protocol client - * - */ - -/* - * - * Copyright (c) 2001-2004 Leon Woestenberg - * Copyright (c) 2001-2004 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. - * - * This file is a contribution to the lwIP TCP/IP stack. - * The Swedish Institute of Computer Science and Adam Dunkels - * are specifically granted permission to redistribute this - * source code. - * - * Author: Leon Woestenberg - * - * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform - * with RFC 2131 and RFC 2132. - * - * TODO: - * - Support for interfaces other than Ethernet (SLIP, PPP, ...) - * - * Please coordinate changes and requests with Leon Woestenberg - * - * - * Integration with your code: - * - * In lwip/dhcp.h - * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute) - * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer) - * - * Then have your application call dhcp_coarse_tmr() and - * dhcp_fine_tmr() on the defined intervals. - * - * dhcp_start(struct netif *netif); - * starts a DHCP client instance which configures the interface by - * obtaining an IP address lease and maintaining it. - * - * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif) - * to remove the DHCP client. - * - */ - -#include "lwip/opt.h" - -#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/stats.h" -#include "lwip/mem.h" -#include "lwip/udp.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/def.h" -#include "lwip/sys.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" -#include "lwip/dns.h" -#include "netif/etharp.h" - -#include - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -/** Default for DHCP_GLOBAL_XID is 0xABCD0000 - * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g. - * #define DHCP_GLOBAL_XID_HEADER "stdlib.h" - * #define DHCP_GLOBAL_XID rand() - */ -#ifdef DHCP_GLOBAL_XID_HEADER -#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */ -#endif - -/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU - * MTU is checked to be big enough in dhcp_start */ -#define DHCP_MAX_MSG_LEN(netif) (netif->mtu) -#define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576 -/** Minimum length for reply before packet is parsed */ -#define DHCP_MIN_REPLY_LEN 44 - -#define REBOOT_TRIES 2 - -/** Option handling: options are parsed in dhcp_parse_reply - * and saved in an array where other functions can load them from. - * This might be moved into the struct dhcp (not necessarily since - * lwIP is single-threaded and the array is only used while in recv - * callback). */ -#define DHCP_OPTION_IDX_OVERLOAD 0 -#define DHCP_OPTION_IDX_MSG_TYPE 1 -#define DHCP_OPTION_IDX_SERVER_ID 2 -#define DHCP_OPTION_IDX_LEASE_TIME 3 -#define DHCP_OPTION_IDX_T1 4 -#define DHCP_OPTION_IDX_T2 5 -#define DHCP_OPTION_IDX_SUBNET_MASK 6 -#define DHCP_OPTION_IDX_ROUTER 7 -#define DHCP_OPTION_IDX_DNS_SERVER 8 -#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS) - -/** Holds the decoded option values, only valid while in dhcp_recv. - @todo: move this into struct dhcp? */ -u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX]; -/** Holds a flag which option was received and is contained in dhcp_rx_options_val, - only valid while in dhcp_recv. - @todo: move this into struct dhcp? */ -u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX]; - -#define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0) -#define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1) -#define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0) -#define dhcp_clear_all_options(dhcp) (os_memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given))) -#define dhcp_get_option_value(dhcp, idx) (dhcp_rx_options_val[idx]) -#define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val)) - - -/* DHCP client state machine functions */ -static err_t dhcp_discover(struct netif *netif); -static err_t dhcp_select(struct netif *netif); -static void dhcp_bind(struct netif *netif); -#if DHCP_DOES_ARP_CHECK -static err_t dhcp_decline(struct netif *netif); -#endif /* DHCP_DOES_ARP_CHECK */ -static err_t dhcp_rebind(struct netif *netif); -static err_t dhcp_reboot(struct netif *netif); -static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state); - -/* receive, unfold, parse and free incoming messages */ -static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); - -/* set the DHCP timers */ -static void dhcp_timeout(struct netif *netif); -static void dhcp_t1_timeout(struct netif *netif); -static void dhcp_t2_timeout(struct netif *netif); - -/* build outgoing messages */ -/* create a DHCP message, fill in common headers */ -static err_t dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type); -/* free a DHCP request */ -static void dhcp_delete_msg(struct dhcp *dhcp); -/* add a DHCP option (type, then length in bytes) */ -static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len); -/* add option values */ -static void dhcp_option_byte(struct dhcp *dhcp, u8_t value); -static void dhcp_option_short(struct dhcp *dhcp, u16_t value); -static void dhcp_option_long(struct dhcp *dhcp, u32_t value); -/* always add the DHCP options trailer to end and pad */ -static void dhcp_option_trailer(struct dhcp *dhcp); - -/** - * Back-off the DHCP client (because of a received NAK response). - * - * Back-off the DHCP client because of a received NAK. Receiving a - * NAK means the client asked for something non-sensible, for - * example when it tries to renew a lease obtained on another network. - * - * We clear any existing set IP address and restart DHCP negotiation - * afresh (as per RFC2131 3.2.3). - * - * @param netif the netif under DHCP control - */ -static void ICACHE_FLASH_ATTR -dhcp_handle_nak(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", - (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - /* Set the interface down since the address must no longer be used, as per RFC2131 */ - netif_set_down(netif); - /* remove IP address from interface */ - netif_set_ipaddr(netif, IP_ADDR_ANY); - netif_set_gw(netif, IP_ADDR_ANY); - netif_set_netmask(netif, IP_ADDR_ANY); - /* Change to a defined state */ - dhcp_set_state(dhcp, DHCP_BACKING_OFF); - /* We can immediately restart discovery */ - dhcp_discover(netif); -} - -#if DHCP_DOES_ARP_CHECK -/** - * Checks if the offered IP address is already in use. - * - * It does so by sending an ARP request for the offered address and - * entering CHECKING state. If no ARP reply is received within a small - * interval, the address is assumed to be free for use by us. - * - * @param netif the netif under DHCP control - */ -static void ICACHE_FLASH_ATTR -dhcp_check(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0], - (s16_t)netif->name[1])); - dhcp_set_state(dhcp, DHCP_CHECKING); - /* create an ARP query for the offered IP address, expecting that no host - responds, as the IP address should not be in use. */ - result = etharp_query(netif, &dhcp->offered_ip_addr, NULL); - if (result != ERR_OK) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_check: could not perform ARP query\n")); - } - dhcp->tries++; - msecs = 500; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs)); -} -#endif /* DHCP_DOES_ARP_CHECK */ - -/** - * Remember the configuration offered by a DHCP server. - * - * @param netif the netif under DHCP control - */ -static void ICACHE_FLASH_ATTR -dhcp_handle_offer(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", - (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - /* obtain the server address */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) { - ip4_addr_set_u32(&dhcp->server_ip_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID))); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", - ip4_addr_get_u32(&dhcp->server_ip_addr))); - /* remember offered address */ - ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", - ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - dhcp_select(netif); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void*)netif)); - } -} - -/** - * Select a DHCP server offer out of all offers. - * - * Simply select the first offer received. - * - * @param netif the netif under DHCP control - * @return lwIP specific error (see error.h) - */ -static err_t ICACHE_FLASH_ATTR -dhcp_select(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - dhcp_set_state(dhcp, DHCP_REQUESTING); - - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - - /* MUST request the offered IP address */ - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->server_ip_addr))); - - dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 12/*num options*/); - dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); - dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); - dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); - dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); - dhcp_option_byte(dhcp, DHCP_OPTION_DOMAIN_NAME); - dhcp_option_byte(dhcp, DHCP_OPTION_NB_TINS); - dhcp_option_byte(dhcp, DHCP_OPTION_NB_TINT); - dhcp_option_byte(dhcp, DHCP_OPTION_NB_TIS); - dhcp_option_byte(dhcp, DHCP_OPTION_PRD); - dhcp_option_byte(dhcp, DHCP_OPTION_STATIC_ROUTER); - dhcp_option_byte(dhcp, DHCP_OPTION_CLASSLESS_STATIC_ROUTER); - dhcp_option_byte(dhcp, DHCP_OPTION_VSN); - -#if LWIP_NETIF_HOSTNAME - if (netif->hostname != NULL) { - const char *p = (const char*)netif->hostname; - u8_t namelen = (u8_t)os_strlen(p); - if (namelen > 0) { - LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); - dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); - while (*p) { - dhcp_option_byte(dhcp, *p++); - } - } - } -#endif /* LWIP_NETIF_HOSTNAME */ - - dhcp_option_trailer(dhcp); - /* shrink the pbuf to the actual content length */ - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - /* send broadcast to any DHCP server */ - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n")); - } - dhcp->tries++; - msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - -/** - * The DHCP timer that checks for lease renewal/rebind timeouts. - */ -void ICACHE_FLASH_ATTR -dhcp_coarse_tmr() -{ - struct netif *netif = netif_list; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); - /* iterate through all network interfaces */ - while (netif != NULL) { - /* only act on DHCP configured interfaces */ - if (netif->dhcp != NULL) { - /* timer is active (non zero), and triggers (zeroes) now? */ - if (netif->dhcp->t2_timeout-- == 1) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n")); - /* this clients' rebind timeout triggered */ - dhcp_t2_timeout(netif); - /* timer is active (non zero), and triggers (zeroes) now */ - } else if (netif->dhcp->t1_timeout-- == 1) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n")); - /* this clients' renewal timeout triggered */ - dhcp_t1_timeout(netif); - } - } - /* proceed to next netif */ - netif = netif->next; - } -} - -/** - * DHCP transaction timeout handling - * - * A DHCP server is expected to respond within a short period of time. - * This timer checks whether an outstanding DHCP request is timed out. - */ -void ICACHE_FLASH_ATTR -dhcp_fine_tmr() -{ - struct netif *netif = netif_list; - /* loop through netif's */ - while (netif != NULL) { - /* only act on DHCP configured interfaces */ - if (netif->dhcp != NULL) { - /*add DHCP retries processing by LiuHan*/ - if (DHCP_MAXRTX != 0) { - if (netif->dhcp->tries >= DHCP_MAXRTX){ - os_printf("DHCP timeout\n"); - if (netif->dhcp_event != NULL) - netif->dhcp_event(); - break; - } - } - /* timer is active (non zero), and is about to trigger now */ - if (netif->dhcp->request_timeout > 1) { - netif->dhcp->request_timeout--; - } - else if (netif->dhcp->request_timeout == 1) { - netif->dhcp->request_timeout--; - /* { netif->dhcp->request_timeout == 0 } */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n")); - /* this client's request timeout triggered */ - dhcp_timeout(netif); - } - } - /* proceed to next network interface */ - netif = netif->next; - } - -} - -/** - * A DHCP negotiation transaction, or ARP request, has timed out. - * - * The timer that was started with the DHCP or ARP request has - * timed out, indicating no response was received in time. - * - * @param netif the netif under DHCP control - */ -static void ICACHE_FLASH_ATTR -dhcp_timeout(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n")); - /* back-off period has passed, or server selection timed out */ - if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n")); - dhcp_discover(netif); - /* receiving the requested lease timed out */ - } else if (dhcp->state == DHCP_REQUESTING) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n")); - if (dhcp->tries <= 5) { - dhcp_select(netif); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n")); - dhcp_release(netif); - dhcp_discover(netif); - } -#if DHCP_DOES_ARP_CHECK - /* received no ARP reply for the offered address (which is good) */ - } else if (dhcp->state == DHCP_CHECKING) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n")); - if (dhcp->tries <= 1) { - dhcp_check(netif); - /* no ARP replies on the offered address, - looks like the IP address is indeed free */ - } else { - /* bind the interface to the offered address */ - dhcp_bind(netif); - } -#endif /* DHCP_DOES_ARP_CHECK */ - } - /* did not get response to renew request? */ - else if (dhcp->state == DHCP_RENEWING) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n")); - /* just retry renewal */ - /* note that the rebind timer will eventually time-out if renew does not work */ - dhcp_renew(netif); - /* did not get response to rebind request? */ - } else if (dhcp->state == DHCP_REBINDING) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n")); - if (dhcp->tries <= 8) { - dhcp_rebind(netif); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n")); - dhcp_release(netif); - dhcp_discover(netif); - } - } else if (dhcp->state == DHCP_REBOOTING) { - if (dhcp->tries < REBOOT_TRIES) { - dhcp_reboot(netif); - } else { - dhcp_discover(netif); - } - } -} - -/** - * The renewal period has timed out. - * - * @param netif the netif under DHCP control - */ -static void ICACHE_FLASH_ATTR -dhcp_t1_timeout(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n")); - if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || - (dhcp->state == DHCP_RENEWING)) { - /* just retry to renew - note that the rebind timer (t2) will - * eventually time-out if renew tries fail. */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("dhcp_t1_timeout(): must renew\n")); - /* This slightly different to RFC2131: DHCPREQUEST will be sent from state - DHCP_RENEWING, not DHCP_BOUND */ - dhcp_renew(netif); - } -} - -/** - * The rebind period has timed out. - * - * @param netif the netif under DHCP control - */ -static void ICACHE_FLASH_ATTR -dhcp_t2_timeout(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n")); - if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || - (dhcp->state == DHCP_RENEWING)) { - /* just retry to rebind */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("dhcp_t2_timeout(): must rebind\n")); - /* This slightly different to RFC2131: DHCPREQUEST will be sent from state - DHCP_REBINDING, not DHCP_BOUND */ - dhcp_rebind(netif); - } -} - -/** - * Handle a DHCP ACK packet - * - * @param netif the netif under DHCP control - */ -static void ICACHE_FLASH_ATTR -dhcp_handle_ack(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; -#if LWIP_DNS - u8_t n; -#endif /* LWIP_DNS */ - - /* clear options we might not get from the ACK */ - ip_addr_set_zero(&dhcp->offered_sn_mask); - ip_addr_set_zero(&dhcp->offered_gw_addr); -#if LWIP_DHCP_BOOTP_FILE - ip_addr_set_zero(&dhcp->offered_si_addr); -#endif /* LWIP_DHCP_BOOTP_FILE */ - - /* lease time given? */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) { - /* remember offered lease time */ - dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME); - } - /* renewal period given? */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) { - /* remember given renewal period */ - dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1); - } else { - /* calculate safe periods for renewal */ - dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2; - } - - /* renewal period given? */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) { - /* remember given rebind period */ - dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2); - } else { - /* calculate safe periods for rebinding */ - dhcp->offered_t2_rebind = dhcp->offered_t0_lease; - } - - /* (y)our internet address */ - ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); - -#if LWIP_DHCP_BOOTP_FILE - /* copy boot server address, - boot file name copied in dhcp_parse_reply if not overloaded */ - ip_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr); -#endif /* LWIP_DHCP_BOOTP_FILE */ - - /* subnet mask given? */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) { - /* remember given subnet mask */ - ip4_addr_set_u32(&dhcp->offered_sn_mask, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK))); - dhcp->subnet_mask_given = 1; - } else { - dhcp->subnet_mask_given = 0; - } - - /* gateway router */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) { - ip4_addr_set_u32(&dhcp->offered_gw_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER))); - } - -#if LWIP_DNS - /* DNS servers */ - n = 0; - while(dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n) && (n < DNS_MAX_SERVERS)) { - ip_addr_t dns_addr; - ip4_addr_set_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n))); - dns_setserver(n, &dns_addr); - n++; - } -#endif /* LWIP_DNS */ -} - -/** Set a statically allocated struct dhcp to work with. - * Using this prevents dhcp_start to allocate it using mem_malloc. - * - * @param netif the netif for which to set the struct dhcp - * @param dhcp (uninitialised) dhcp struct allocated by the application - */ -void ICACHE_FLASH_ATTR -dhcp_set_struct(struct netif *netif, struct dhcp *dhcp) -{ - LWIP_ASSERT("netif != NULL", netif != NULL); - LWIP_ASSERT("dhcp != NULL", dhcp != NULL); - LWIP_ASSERT("netif already has a struct dhcp set", netif->dhcp == NULL); - - /* clear data structure */ - os_memset(dhcp, 0, sizeof(struct dhcp)); - /* dhcp_set_state(&dhcp, DHCP_OFF); */ - netif->dhcp = dhcp; -} - -/** Removes a struct dhcp from a netif. - * - * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the - * struct dhcp since the memory is passed back to the heap. - * - * @param netif the netif from which to remove the struct dhcp - */ -void ICACHE_FLASH_ATTR dhcp_cleanup(struct netif *netif) -{ - LWIP_ASSERT("netif != NULL", netif != NULL); - - if (netif->dhcp != NULL) { - mem_free(netif->dhcp); - netif->dhcp = NULL; - } -} - -/** - * Start DHCP negotiation for a network interface. - * - * If no DHCP client instance was attached to this interface, - * a new client is created first. If a DHCP client instance - * was already present, it restarts negotiation. - * - * @param netif The lwIP network interface - * @return lwIP error code - * - ERR_OK - No error - * - ERR_MEM - Out of memory - */ -err_t ICACHE_FLASH_ATTR -dhcp_start(struct netif *netif) -{ - struct dhcp *dhcp; - err_t result = ERR_OK; - LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;); - dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - /* Remove the flag that says this netif is handled by DHCP, - it is set when we succeeded starting. */ - netif->flags &= ~NETIF_FLAG_DHCP; - - /* check hwtype of the netif */ - if ((netif->flags & NETIF_FLAG_ETHARP) == 0) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): No ETHARP netif\n")); - return ERR_ARG; - } - - /* check MTU of the netif */ - if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n")); - return ERR_MEM; - } - - /* no DHCP client attached yet? */ - if (dhcp == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n")); - dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp)); - if (dhcp == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n")); - return ERR_MEM; - } - /* store this dhcp client in the netif */ - netif->dhcp = dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp")); - /* already has DHCP client attached */ - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n")); - if (dhcp->pcb != NULL) { - udp_remove(dhcp->pcb); - } - LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL); - LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL ); - } - - /* clear data structure */ - os_memset(dhcp, 0, sizeof(struct dhcp)); - /* dhcp_set_state(&dhcp, DHCP_OFF); */ - /* allocate UDP PCB */ - dhcp->pcb = udp_new(); - if (dhcp->pcb == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n")); - return ERR_MEM; - } - dhcp->pcb->so_options |= SOF_BROADCAST; - /* set up local and remote port for the pcb */ - udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); - udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); - /* set up the recv callback and argument */ - udp_recv(dhcp->pcb, dhcp_recv, netif); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n")); - /* (re)start the DHCP negotiation */ - result = dhcp_discover(netif); - if (result != ERR_OK) { - /* free resources allocated above */ - dhcp_stop(netif); - return ERR_MEM; - } - /* Set the flag that says this netif is handled by DHCP. */ - netif->flags |= NETIF_FLAG_DHCP; - return result; -} - -/** - * Inform a DHCP server of our manual configuration. - * - * This informs DHCP servers of our fixed IP address configuration - * by sending an INFORM message. It does not involve DHCP address - * configuration, it is just here to be nice to the network. - * - * @param netif The lwIP network interface - */ -void ICACHE_FLASH_ATTR -dhcp_inform(struct netif *netif) -{ - struct dhcp dhcp; - err_t result = ERR_OK; - struct udp_pcb *pcb; - - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - - os_memset(&dhcp, 0, sizeof(struct dhcp)); - dhcp_set_state(&dhcp, DHCP_INFORM); - - if ((netif->dhcp != NULL) && (netif->dhcp->pcb != NULL)) { - /* re-use existing pcb */ - pcb = netif->dhcp->pcb; - } else { - pcb = udp_new(); - if (pcb == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not obtain pcb")); - return; - } - dhcp.pcb = pcb; - dhcp.pcb->so_options |= SOF_BROADCAST; - udp_bind(dhcp.pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n")); - } - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, &dhcp, DHCP_INFORM); - if (result == ERR_OK) { - dhcp_option(&dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(&dhcp, DHCP_MAX_MSG_LEN(netif)); - - dhcp_option_trailer(&dhcp); - - pbuf_realloc(dhcp.p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp.options_out_len); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); - udp_sendto_if(pcb, dhcp.p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(&dhcp); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n")); - } - - if (dhcp.pcb != NULL) { - /* otherwise, the existing pcb was used */ - udp_remove(dhcp.pcb); - } -} - -/** Handle a possible change in the network configuration. - * - * This enters the REBOOTING state to verify that the currently bound - * address is still valid. - */ -void ICACHE_FLASH_ATTR -dhcp_network_changed(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - if (!dhcp) - return; - switch (dhcp->state) { - case DHCP_REBINDING: - case DHCP_RENEWING: - case DHCP_BOUND: - case DHCP_REBOOTING: - netif_set_down(netif); - dhcp->tries = 0; - dhcp_reboot(netif); - break; - case DHCP_OFF: - /* stay off */ - break; - default: - dhcp->tries = 0; -#if LWIP_DHCP_AUTOIP_COOP - if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { - autoip_stop(netif); - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ - dhcp_discover(netif); - break; - } -} - -#if DHCP_DOES_ARP_CHECK -/** - * Match an ARP reply with the offered IP address. - * - * @param netif the network interface on which the reply was received - * @param addr The IP address we received a reply from - */ -void ICACHE_FLASH_ATTR dhcp_arp_reply(struct netif *netif, ip_addr_t *addr) -{ - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n")); - /* is a DHCP client doing an ARP check? */ - if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", - ip4_addr_get_u32(addr))); - /* did a host respond with the address we - were offered by the DHCP server? */ - if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) { - /* we will not accept the offered address */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, - ("dhcp_arp_reply(): arp reply matched with offered address, declining\n")); - dhcp_decline(netif); - } - } -} - -/** - * Decline an offered lease. - * - * Tell the DHCP server we do not accept the offered address. - * One reason to decline the lease is when we find out the address - * is already in use by another host (through ARP). - * - * @param netif the netif under DHCP control - */ -static err_t ICACHE_FLASH_ATTR -dhcp_decline(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result = ERR_OK; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n")); - dhcp_set_state(dhcp, DHCP_BACKING_OFF); - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - dhcp_option_trailer(dhcp); - /* resize pbuf to reflect true size of options */ - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - /* per section 4.4.4, broadcast DECLINE messages */ - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_decline: could not allocate DHCP request\n")); - } - dhcp->tries++; - msecs = 10*1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} -#endif /* DHCP_DOES_ARP_CHECK */ - - -/** - * Start the DHCP process, discover a DHCP server. - * - * @param netif the netif under DHCP control - */ -static err_t ICACHE_FLASH_ATTR -dhcp_discover(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result = ERR_OK; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n")); - ip_addr_set_any(&dhcp->offered_ip_addr); - dhcp_set_state(dhcp, DHCP_SELECTING); - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER); - if (result == ERR_OK) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n")); - - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - -#if LWIP_NETIF_HOSTNAME - if (netif->hostname != NULL) { - const char *p = (const char*)netif->hostname; - u8_t namelen = (u8_t)os_strlen(p); - if (namelen > 0) { - LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); - dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); - while (*p) { - dhcp_option_byte(dhcp, *p++); - } - } - } -#endif /* LWIP_NETIF_HOSTNAME */ - dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 12/*num options*/); - dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); - dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); - dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); - dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); - dhcp_option_byte(dhcp, DHCP_OPTION_DOMAIN_NAME); - dhcp_option_byte(dhcp, DHCP_OPTION_NB_TINS); - dhcp_option_byte(dhcp, DHCP_OPTION_NB_TINT); - dhcp_option_byte(dhcp, DHCP_OPTION_NB_TIS); - dhcp_option_byte(dhcp, DHCP_OPTION_PRD); - dhcp_option_byte(dhcp, DHCP_OPTION_STATIC_ROUTER); - dhcp_option_byte(dhcp, DHCP_OPTION_CLASSLESS_STATIC_ROUTER); - dhcp_option_byte(dhcp, DHCP_OPTION_VSN); - - dhcp_option_trailer(dhcp); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n")); - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n")); - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n")); - } - dhcp->tries++; -#if LWIP_DHCP_AUTOIP_COOP - if(dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) { - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON; - autoip_start(netif); - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ - msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - - -/** - * Bind the interface to the offered IP address. - * - * @param netif network interface to bind to the offered address - */ -static void ICACHE_FLASH_ATTR -dhcp_bind(struct netif *netif) -{ - u32_t timeout; - struct dhcp *dhcp; - ip_addr_t sn_mask, gw_addr; - LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;); - dhcp = netif->dhcp; - LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - - /* temporary DHCP lease? */ - if (dhcp->offered_t1_renew != 0xffffffffUL) { - /* set renewal period timer */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew)); - timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; - if(timeout > 0xffff) { - timeout = 0xffff; - } - dhcp->t1_timeout = (u16_t)timeout; - if (dhcp->t1_timeout == 0) { - dhcp->t1_timeout = 1; - } - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000)); - } - /* set renewal period timer */ - if (dhcp->offered_t2_rebind != 0xffffffffUL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind)); - timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; - if(timeout > 0xffff) { - timeout = 0xffff; - } - dhcp->t2_timeout = (u16_t)timeout; - if (dhcp->t2_timeout == 0) { - dhcp->t2_timeout = 1; - } - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000)); - } - - /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. modify by ives at 2014.4.22*/ - if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) { - dhcp->t1_timeout = 0; - } - - if (dhcp->subnet_mask_given) { - /* copy offered network mask */ - ip_addr_copy(sn_mask, dhcp->offered_sn_mask); - } else { - /* subnet mask not given, choose a safe subnet mask given the network class */ - u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr); - if (first_octet <= 127) { - ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000)); - } else if (first_octet >= 192) { - ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00)); - } else { - ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000)); - } - } - - ip_addr_copy(gw_addr, dhcp->offered_gw_addr); - /* gateway address not given? */ - if (ip_addr_isany(&gw_addr)) { - /* copy network address */ - ip_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask); - /* use first host address on network as gateway */ - ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001)); - } - -#if LWIP_DHCP_AUTOIP_COOP - if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { - autoip_stop(netif); - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ - - // wjg:back up old ip/netmask/gw - ip_addr_t ip, mask, gw; - ip = netif->ip_addr; - mask = netif->netmask; - gw = netif->gw; - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", - ip4_addr_get_u32(&dhcp->offered_ip_addr))); - netif_set_ipaddr(netif, &dhcp->offered_ip_addr); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", - ip4_addr_get_u32(&sn_mask))); - netif_set_netmask(netif, &sn_mask); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", - ip4_addr_get_u32(&gw_addr))); - netif_set_gw(netif, &gw_addr); - - /* bring the interface up */ - netif_set_up(netif); - - // wjg: use old ip/mask/gw to check whether ip/mask/gw changed - system_station_got_ip_set(&ip, &mask, &gw); - - /* netif is now bound to DHCP leased address */ - dhcp_set_state(dhcp, DHCP_BOUND); -} - -/** - * Renew an existing DHCP lease at the involved DHCP server. - * - * @param netif network interface which must renew its lease - */ -err_t ICACHE_FLASH_ATTR -dhcp_renew(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n")); - dhcp_set_state(dhcp, DHCP_RENEWING); - - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - -#if LWIP_NETIF_HOSTNAME - if (netif->hostname != NULL) { - const char *p = (const char*)netif->hostname; - u8_t namelen = (u8_t)os_strlen(p); - if (namelen > 0) { - LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); - dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); - while (*p) { - dhcp_option_byte(dhcp, *p++); - } - } - } -#endif /* LWIP_NETIF_HOSTNAME */ - -#if 1 - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); -#endif - -#if 1 - dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); - dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); -#endif - /* append DHCP message trailer */ - dhcp_option_trailer(dhcp); - - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n")); - } - dhcp->tries++; - /* back-off on retries, but to a maximum of 20 seconds */ - msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - -/** - * Rebind with a DHCP server for an existing DHCP lease. - * - * @param netif network interface which must rebind with a DHCP server - */ -static err_t ICACHE_FLASH_ATTR -dhcp_rebind(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n")); - dhcp_set_state(dhcp, DHCP_REBINDING); - - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - -#if LWIP_NETIF_HOSTNAME - if (netif->hostname != NULL) { - const char *p = (const char*)netif->hostname; - u8_t namelen = (u8_t)os_strlen(p); - if (namelen > 0) { - LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); - dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); - while (*p) { - dhcp_option_byte(dhcp, *p++); - } - } - } -#endif /* LWIP_NETIF_HOSTNAME */ - -#if 1 - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); - - dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); - dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); -#endif - - dhcp_option_trailer(dhcp); - - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - /* broadcast to server */ - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n")); - } - dhcp->tries++; - msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - -/** - * Enter REBOOTING state to verify an existing lease - * - * @param netif network interface which must reboot - */ -static err_t ICACHE_FLASH_ATTR -dhcp_reboot(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n")); - dhcp_set_state(dhcp, DHCP_REBOOTING); - - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, 576); - - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - dhcp_option_trailer(dhcp); - - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - /* broadcast to server */ - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n")); - } - dhcp->tries++; - msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - - -/** - * Release a DHCP lease. - * - * @param netif network interface which must release its lease - */ -err_t ICACHE_FLASH_ATTR -dhcp_release(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n")); - if (dhcp == NULL) { - return ERR_ARG; - } - - /* idle DHCP client */ - dhcp_set_state(dhcp, DHCP_OFF); - /* clean old DHCP offer */ - ip_addr_set_zero(&dhcp->server_ip_addr); - ip_addr_set_zero(&dhcp->offered_ip_addr); - ip_addr_set_zero(&dhcp->offered_sn_mask); - ip_addr_set_zero(&dhcp->offered_gw_addr); -#if LWIP_DHCP_BOOTP_FILE - ip_addr_set_zero(&dhcp->offered_si_addr); -#endif /* LWIP_DHCP_BOOTP_FILE */ - dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; - - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE); - if (result == ERR_OK) { - dhcp_option_trailer(dhcp); - - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n")); - } - dhcp->tries++; - msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs)); - /* bring the interface down */ - netif_set_down(netif); - /* remove IP address from interface */ - netif_set_ipaddr(netif, IP_ADDR_ANY); - netif_set_gw(netif, IP_ADDR_ANY); - netif_set_netmask(netif, IP_ADDR_ANY); - - return result; -} - -/** - * Remove the DHCP client from the interface. - * - * @param netif The network interface to stop DHCP on - */ -void ICACHE_FLASH_ATTR -dhcp_stop(struct netif *netif) -{ - struct dhcp *dhcp; - LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;); - dhcp = netif->dhcp; - /* Remove the flag that says this netif is handled by DHCP. */ - netif->flags &= ~NETIF_FLAG_DHCP; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n")); - /* netif is DHCP configured? */ - if (dhcp != NULL) { -#if LWIP_DHCP_AUTOIP_COOP - if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { - autoip_stop(netif); - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ - - if (dhcp->pcb != NULL) { - udp_remove(dhcp->pcb); - dhcp->pcb = NULL; - } - LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); - dhcp_set_state(dhcp, DHCP_OFF); - } -} - -/* - * Set the DHCP state of a DHCP client. - * - * If the state changed, reset the number of tries. - */ -static void ICACHE_FLASH_ATTR -dhcp_set_state(struct dhcp *dhcp, u8_t new_state) -{ - if (new_state != dhcp->state) { - dhcp->state = new_state; - dhcp->tries = 0; - dhcp->request_timeout = 0; - } -} - -/* - * Concatenate an option type and length field to the outgoing - * DHCP message. - * - */ -static void ICACHE_FLASH_ATTR -dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len) -{ - LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = option_type; - dhcp->msg_out->options[dhcp->options_out_len++] = option_len; -} -/* - * Concatenate a single byte to the outgoing DHCP message. - * - */ -static void ICACHE_FLASH_ATTR -dhcp_option_byte(struct dhcp *dhcp, u8_t value) -{ - LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = value; -} - -static void ICACHE_FLASH_ATTR -dhcp_option_short(struct dhcp *dhcp, u16_t value) -{ - LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU); -} - -static void ICACHE_FLASH_ATTR -dhcp_option_long(struct dhcp *dhcp, u32_t value) -{ - LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL)); -} - -/** - * Extract the DHCP message and the DHCP options. - * - * Extract the DHCP message and the DHCP options, each into a contiguous - * piece of memory. As a DHCP message is variable sized by its options, - * and also allows overriding some fields for options, the easy approach - * is to first unfold the options into a conitguous piece of memory, and - * use that further on. - * - */ -static err_t ICACHE_FLASH_ATTR -dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p) -{ - u8_t *options; - u16_t offset; - u16_t offset_max; - u16_t options_idx; - u16_t options_idx_max; - struct pbuf *q; - int parse_file_as_options = 0; - int parse_sname_as_options = 0; - - /* clear received options */ - dhcp_clear_all_options(dhcp); - /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */ - if (p->len < DHCP_SNAME_OFS) { - return ERR_BUF; - } - dhcp->msg_in = (struct dhcp_msg *)p->payload; -#if LWIP_DHCP_BOOTP_FILE - /* clear boot file name */ - dhcp->boot_file_name[0] = 0; -#endif /* LWIP_DHCP_BOOTP_FILE */ - - /* parse options */ - - /* start with options field */ - options_idx = DHCP_OPTIONS_OFS; - /* parse options to the end of the received packet */ - options_idx_max = p->tot_len; -again: - q = p; - while((q != NULL) && (options_idx >= q->len)) { - options_idx -= q->len; - options_idx_max -= q->len; - q = q->next; - } - if (q == NULL) { - return ERR_BUF; - } - offset = options_idx; - offset_max = options_idx_max; - options = (u8_t*)q->payload; - /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ - while((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < offset_max)) { - u8_t op = options[offset]; - u8_t len; - u8_t decode_len = 0; - int decode_idx = -1; - u16_t val_offset = offset + 2; - /* len byte might be in the next pbuf */ - if (offset + 1 < q->len) { - len = options[offset + 1]; - } else { - len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0); - } - /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ - decode_len = len; - switch(op) { - /* case(DHCP_OPTION_END): handled above */ - case(DHCP_OPTION_PAD): - /* special option: no len encoded */ - decode_len = len = 0; - /* will be increased below */ - offset--; - break; - case(DHCP_OPTION_SUBNET_MASK): - LWIP_ASSERT("len == 4", len == 4); - decode_idx = DHCP_OPTION_IDX_SUBNET_MASK; - break; - case(DHCP_OPTION_ROUTER): - decode_len = 4; /* only copy the first given router */ - LWIP_ASSERT("len >= decode_len", len >= decode_len); - decode_idx = DHCP_OPTION_IDX_ROUTER; - break; - case(DHCP_OPTION_DNS_SERVER): - /* special case: there might be more than one server */ - LWIP_ASSERT("len % 4 == 0", len % 4 == 0); - /* limit number of DNS servers */ - decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS); - LWIP_ASSERT("len >= decode_len", len >= decode_len); - decode_idx = DHCP_OPTION_IDX_DNS_SERVER; - break; - case(DHCP_OPTION_LEASE_TIME): - LWIP_ASSERT("len == 4", len == 4); - decode_idx = DHCP_OPTION_IDX_LEASE_TIME; - break; - case(DHCP_OPTION_OVERLOAD): - LWIP_ASSERT("len == 1", len == 1); - decode_idx = DHCP_OPTION_IDX_OVERLOAD; - break; - case(DHCP_OPTION_MESSAGE_TYPE): - LWIP_ASSERT("len == 1", len == 1); - decode_idx = DHCP_OPTION_IDX_MSG_TYPE; - break; - case(DHCP_OPTION_SERVER_ID): - LWIP_ASSERT("len == 4", len == 4); - decode_idx = DHCP_OPTION_IDX_SERVER_ID; - break; - case(DHCP_OPTION_T1): - LWIP_ASSERT("len == 4", len == 4); - decode_idx = DHCP_OPTION_IDX_T1; - break; - case(DHCP_OPTION_T2): - LWIP_ASSERT("len == 4", len == 4); - decode_idx = DHCP_OPTION_IDX_T2; - break; - default: - decode_len = 0; - LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", op)); - break; - } - offset += len + 2; - if (decode_len > 0) { - u32_t value = 0; - u16_t copy_len; -decode_next: - LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX); - LWIP_ASSERT("option already decoded", !dhcp_option_given(dhcp, decode_idx)); - copy_len = LWIP_MIN(decode_len, 4); - pbuf_copy_partial(q, &value, copy_len, val_offset); - if (decode_len > 4) { - /* decode more than one u32_t */ - LWIP_ASSERT("decode_len % 4 == 0", decode_len % 4 == 0); - dhcp_got_option(dhcp, decode_idx); - dhcp_set_option_value(dhcp, decode_idx, htonl(value)); - decode_len -= 4; - val_offset += 4; - decode_idx++; - goto decode_next; - } else if (decode_len == 4) { - value = ntohl(value); - } else { - LWIP_ASSERT("invalid decode_len", decode_len == 1); - value = ((u8_t*)&value)[0]; - } - dhcp_got_option(dhcp, decode_idx); - dhcp_set_option_value(dhcp, decode_idx, value); - } - if (offset >= q->len) { - offset -= q->len; - offset_max -= q->len; - if ((offset < offset_max) && offset_max) { //modify by ives at 2014.4.22 - q = q->next; - LWIP_ASSERT("next pbuf was null", q); - options = (u8_t*)q->payload; - } else { - /* We've run out of bytes, probably no end marker. Don't proceed. */ - break; - } - } - } - /* is this an overloaded message? */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) { - u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD); - dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD); - if (overload == DHCP_OVERLOAD_FILE) { - parse_file_as_options = 1; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n")); - } else if (overload == DHCP_OVERLOAD_SNAME) { - parse_sname_as_options = 1; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n")); - } else if (overload == DHCP_OVERLOAD_SNAME_FILE) { - parse_sname_as_options = 1; - parse_file_as_options = 1; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload)); - } -#if LWIP_DHCP_BOOTP_FILE - if (!parse_file_as_options) { - /* only do this for ACK messages */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) && - (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) - /* copy bootp file name, don't care for sname (server hostname) */ - pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS); - /* make sure the string is really NULL-terminated */ - dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0; - } -#endif /* LWIP_DHCP_BOOTP_FILE */ - } - if (parse_file_as_options) { - /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */ - parse_file_as_options = 0; - options_idx = DHCP_FILE_OFS; - options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN; - goto again; - } else if (parse_sname_as_options) { - parse_sname_as_options = 0; - options_idx = DHCP_SNAME_OFS; - options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN; - goto again; - } - return ERR_OK; -} - -/** - * If an incoming DHCP message is in response to us, then trigger the state machine - */ -static void ICACHE_FLASH_ATTR -dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) -{ - struct netif *netif = (struct netif *)arg; - struct dhcp *dhcp = netif->dhcp; - struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; - u8_t msg_type; - u8_t i; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p, - ip4_addr1_16(addr), ip4_addr2_16(addr), ip4_addr3_16(addr), ip4_addr4_16(addr), port)); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len)); - /* prevent warnings about unused arguments */ - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(addr); - LWIP_UNUSED_ARG(port); - - LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); - - if (p->len < DHCP_MIN_REPLY_LEN) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n")); - goto free_pbuf_and_return; - } - - if (reply_msg->op != DHCP_BOOTREPLY) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op)); - goto free_pbuf_and_return; - } - /* iterate through hardware address and match against DHCP message */ - for (i = 0; i < netif->hwaddr_len; i++) { - if (netif->hwaddr[i] != reply_msg->chaddr[i]) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n", - (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i])); - goto free_pbuf_and_return; - } - } - /* match transaction ID against what we expected */ - if (ntohl(reply_msg->xid) != dhcp->xid) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid)); - goto free_pbuf_and_return; - } - /* option fields could be unfold? */ - if (dhcp_parse_reply(dhcp, p) != ERR_OK) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("problem unfolding DHCP message - too short on memory?\n")); - goto free_pbuf_and_return; - } - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n")); - /* obtain pointer to DHCP message type */ - if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); - goto free_pbuf_and_return; - } - - /* read DHCP message type */ - msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE); - /* message type is DHCP ACK? */ - if (msg_type == DHCP_ACK) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n")); - /* in requesting state? */ - if (dhcp->state == DHCP_REQUESTING) { - dhcp_handle_ack(netif); -#if DHCP_DOES_ARP_CHECK - /* check if the acknowledged lease address is already in use */ - dhcp_check(netif); -#else - /* bind interface to the acknowledged lease address */ - dhcp_bind(netif); -#endif - } - /* already bound to the given lease address? */ - else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) { - dhcp_bind(netif); - } - } - /* received a DHCP_NAK in appropriate state? */ - else if ((msg_type == DHCP_NAK) && - ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) || - (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n")); - dhcp_handle_nak(netif); - } - /* received a DHCP_OFFER in DHCP_SELECTING state? */ - else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_SELECTING state\n")); - dhcp->request_timeout = 0; - /* remember offered lease */ - dhcp_handle_offer(netif); - } -free_pbuf_and_return: - dhcp->msg_in = NULL; - pbuf_free(p); -} - -/** - * Create a DHCP request, fill in common headers - * - * @param netif the netif under DHCP control - * @param dhcp dhcp control struct - * @param message_type message type of the request - */ -static err_t ICACHE_FLASH_ATTR -dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type) -{ - u16_t i; -#ifndef DHCP_GLOBAL_XID - /** default global transaction identifier starting value (easy to match - * with a packet analyser). We simply increment for each new request. - * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one - * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */ - static u32_t xid = 0xABCD0000; -#else - static u32_t xid; - static u8_t xid_initialised = 0; - if (!xid_initialised) { - xid = DHCP_GLOBAL_XID; - xid_initialised = !xid_initialised; - } -#endif - LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return ERR_ARG;); - LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); - LWIP_ASSERT("dhcp_create_msg: dhcp->p_out == NULL", dhcp->p_out == NULL); - LWIP_ASSERT("dhcp_create_msg: dhcp->msg_out == NULL", dhcp->msg_out == NULL); - dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); - if (dhcp->p_out == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_create_msg(): could not allocate pbuf\n")); - return ERR_MEM; - } - LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg", - (dhcp->p_out->len >= sizeof(struct dhcp_msg))); - - /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER modify by ives at 2014.4.22*/ - if (message_type != DHCP_REQUEST) { - /* reuse transaction identifier in retransmissions */ - if (dhcp->tries == 0) { - xid++; - } - dhcp->xid = xid; - } - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, - ("transaction id xid(%"X32_F")\n", xid)); - - dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload; - - dhcp->msg_out->op = DHCP_BOOTREQUEST; - /* TODO: make link layer independent */ - dhcp->msg_out->htype = DHCP_HTYPE_ETH; - dhcp->msg_out->hlen = netif->hwaddr_len; - dhcp->msg_out->hops = 0; - dhcp->msg_out->xid = htonl(dhcp->xid); - dhcp->msg_out->secs = 0; - /* we don't need the broadcast flag since we can receive unicast traffic - before being fully configured! */ - dhcp->msg_out->flags = 0; - ip_addr_set_zero(&dhcp->msg_out->ciaddr); - /* set ciaddr to netif->ip_addr based on message_type and state */ - if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) || - ((message_type == DHCP_REQUEST) && /* DHCP_BOUND not used for sending! */ - ((dhcp->state==DHCP_RENEWING) || dhcp->state==DHCP_REBINDING))) { - ip_addr_copy(dhcp->msg_out->ciaddr, netif->ip_addr); - } - ip_addr_set_zero(&dhcp->msg_out->yiaddr); - ip_addr_set_zero(&dhcp->msg_out->siaddr); - ip_addr_set_zero(&dhcp->msg_out->giaddr); - for (i = 0; i < DHCP_CHADDR_LEN; i++) { - /* copy netif hardware address, pad with zeroes */ - dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len && i < NETIF_MAX_HWADDR_LEN) ? netif->hwaddr[i] : 0/* pad byte*/; - } - for (i = 0; i < DHCP_SNAME_LEN; i++) { - dhcp->msg_out->sname[i] = 0; - } - for (i = 0; i < DHCP_FILE_LEN; i++) { - dhcp->msg_out->file[i] = 0; - } - dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE); - dhcp->options_out_len = 0; - /* fill options field with an incrementing array (for debugging purposes) */ - for (i = 0; i < DHCP_OPTIONS_LEN; i++) { - dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */ - } - /* Add option MESSAGE_TYPE */ - dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); - dhcp_option_byte(dhcp, message_type); - return ERR_OK; -} - -/** - * Free previously allocated memory used to send a DHCP request. - * - * @param dhcp the dhcp struct to free the request from - */ -static void ICACHE_FLASH_ATTR -dhcp_delete_msg(struct dhcp *dhcp) -{ - LWIP_ERROR("dhcp_delete_msg: dhcp != NULL", (dhcp != NULL), return;); - LWIP_ASSERT("dhcp_delete_msg: dhcp->p_out != NULL", dhcp->p_out != NULL); - LWIP_ASSERT("dhcp_delete_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL); - if (dhcp->p_out != NULL) { - pbuf_free(dhcp->p_out); - } - dhcp->p_out = NULL; - dhcp->msg_out = NULL; -} - -/** - * Add a DHCP message trailer - * - * Adds the END option to the DHCP message, and if - * necessary, up to three padding bytes. - * - * @param dhcp DHCP state structure - */ -static void ICACHE_FLASH_ATTR -dhcp_option_trailer(struct dhcp *dhcp) -{ - LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;); - LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL); - LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END; - /* packet is too small, or not 4 byte aligned? */ - while (((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) && - (dhcp->options_out_len < DHCP_OPTIONS_LEN)) { - /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */ - LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); - /* add a fill/padding byte */ - dhcp->msg_out->options[dhcp->options_out_len++] = 0; - } -} - -#endif /* LWIP_DHCP */ diff --git a/tools/sdk/lwip/src/core/dns.c b/tools/sdk/lwip/src/core/dns.c deleted file mode 100755 index 5e75f6d5a..000000000 --- a/tools/sdk/lwip/src/core/dns.c +++ /dev/null @@ -1,988 +0,0 @@ -/** - * @file - * DNS - host name to IP address resolver. - * - */ - -/** - - * This file implements a DNS host name to IP address resolver. - - * Port to lwIP from uIP - * by Jim Pettinato April 2007 - - * uIP version Copyright (c) 2002-2003, Adam Dunkels. - * 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. - * - * - * DNS.C - * - * The lwIP DNS resolver functions are used to lookup a host name and - * map it to a numerical IP address. It maintains a list of resolved - * hostnames that can be queried with the dns_lookup() function. - * New hostnames can be resolved using the dns_query() function. - * - * The lwIP version of the resolver also adds a non-blocking version of - * gethostbyname() that will work with a raw API application. This function - * checks for an IP address string first and converts it if it is valid. - * gethostbyname() then does a dns_lookup() to see if the name is - * already in the table. If so, the IP is returned. If not, a query is - * issued and the function returns with a ERR_INPROGRESS status. The app - * using the dns client must then go into a waiting state. - * - * Once a hostname has been resolved (or found to be non-existent), - * the resolver code calls a specified callback function (which - * must be implemented by the module that uses the resolver). - */ - -/*----------------------------------------------------------------------------- - * RFC 1035 - Domain names - implementation and specification - * RFC 2181 - Clarifications to the DNS Specification - *----------------------------------------------------------------------------*/ - -/** @todo: define good default values (rfc compliance) */ -/** @todo: improve answer parsing, more checkings... */ -/** @todo: check RFC1035 - 7.3. Processing responses */ - -/*----------------------------------------------------------------------------- - * Includes - *----------------------------------------------------------------------------*/ - -#include "lwip/opt.h" - -#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/udp.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/dns.h" - -#include - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -/** DNS server IP address */ -#ifndef DNS_SERVER_ADDRESS -#define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, 0xDEDE43D0)) /* resolver1.opendns.com(208.67.222.222) */ -#endif - -/** DNS server port address */ -#ifndef DNS_SERVER_PORT -#define DNS_SERVER_PORT 53 -#endif - -/** DNS maximum number of retries when asking for a name, before "timeout". */ -#ifndef DNS_MAX_RETRIES -#define DNS_MAX_RETRIES 4 -#endif - -/** DNS resource record max. TTL (one week as default) */ -#ifndef DNS_MAX_TTL -#define DNS_MAX_TTL 604800 -#endif - -/* DNS protocol flags */ -#define DNS_FLAG1_RESPONSE 0x80 -#define DNS_FLAG1_OPCODE_STATUS 0x10 -#define DNS_FLAG1_OPCODE_INVERSE 0x08 -#define DNS_FLAG1_OPCODE_STANDARD 0x00 -#define DNS_FLAG1_AUTHORATIVE 0x04 -#define DNS_FLAG1_TRUNC 0x02 -#define DNS_FLAG1_RD 0x01 -#define DNS_FLAG2_RA 0x80 -#define DNS_FLAG2_ERR_MASK 0x0f -#define DNS_FLAG2_ERR_NONE 0x00 -#define DNS_FLAG2_ERR_NAME 0x03 - -/* DNS protocol states */ -#define DNS_STATE_UNUSED 0 -#define DNS_STATE_NEW 1 -#define DNS_STATE_ASKING 2 -#define DNS_STATE_DONE 3 - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** DNS message header */ -struct dns_hdr { - PACK_STRUCT_FIELD(u16_t id); - PACK_STRUCT_FIELD(u8_t flags1); - PACK_STRUCT_FIELD(u8_t flags2); - PACK_STRUCT_FIELD(u16_t numquestions); - PACK_STRUCT_FIELD(u16_t numanswers); - PACK_STRUCT_FIELD(u16_t numauthrr); - PACK_STRUCT_FIELD(u16_t numextrarr); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -#define SIZEOF_DNS_HDR 12 - -/** DNS query message structure. - No packing needed: only used locally on the stack. */ -struct dns_query { - /* DNS query record starts with either a domain name or a pointer - to a name already present somewhere in the packet. */ - u16_t type; - u16_t cls; -}; -#define SIZEOF_DNS_QUERY 4 - -/** DNS answer message structure. - No packing needed: only used locally on the stack. */ -struct dns_answer { - /* DNS answer record starts with either a domain name or a pointer - to a name already present somewhere in the packet. */ - u16_t type; - u16_t cls; - u32_t ttl; - u16_t len; -}; -#define SIZEOF_DNS_ANSWER 10 - -/** DNS table entry */ -struct dns_table_entry { - u8_t state; - u8_t numdns; - u8_t tmr; - u8_t retries; - u8_t seqno; - u8_t err; - u32_t ttl; - char name[DNS_MAX_NAME_LENGTH]; - ip_addr_t ipaddr; - /* pointer to callback on DNS query done */ - dns_found_callback found; - void *arg; -}; - -#if DNS_LOCAL_HOSTLIST - -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC -/** Local host-list. For hostnames in this list, no - * external name resolution is performed */ -static struct local_hostlist_entry *local_hostlist_dynamic; -#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - -/** Defining this allows the local_hostlist_static to be placed in a different - * linker section (e.g. FLASH) */ -#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE -#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static -#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */ -/** Defining this allows the local_hostlist_static to be placed in a different - * linker section (e.g. FLASH) */ -#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST -#define DNS_LOCAL_HOSTLIST_STORAGE_POST -#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */ -DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[] - DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT; - -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - -static void dns_init_local(); -#endif /* DNS_LOCAL_HOSTLIST */ - - -/* forward declarations */ -static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); -static void dns_check_entries(void); - -/*----------------------------------------------------------------------------- - * Globales - *----------------------------------------------------------------------------*/ - -/* DNS variables */ -static struct udp_pcb *dns_pcb; -static u8_t dns_seqno; -static struct dns_table_entry dns_table[DNS_TABLE_SIZE]; -static ip_addr_t dns_servers[DNS_MAX_SERVERS]; -/** Contiguous buffer for processing responses */ -//static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)]; -static u8_t* dns_payload; -static u16_t dns_random; -/** - * Initialize the resolver: set up the UDP pcb and configure the default server - * (DNS_SERVER_ADDRESS). - */ -void ICACHE_FLASH_ATTR -dns_init() -{ - ip_addr_t dnsserver; - -// dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer); - - /* initialize default DNS server address */ - DNS_SERVER_ADDRESS(&dnsserver); - - LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); - - /* if dns client not yet initialized... */ - if (dns_pcb == NULL) { - dns_pcb = udp_new(); - - if (dns_pcb != NULL) { - /* initialize DNS table not needed (initialized to zero since it is a - * global variable) */ - LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0", - DNS_STATE_UNUSED == 0); - - /* initialize DNS client */ - udp_bind(dns_pcb, IP_ADDR_ANY, 0); - udp_recv(dns_pcb, dns_recv, NULL); - - /* initialize default DNS primary server */ - dns_setserver(0, &dnsserver); - } - } -#if DNS_LOCAL_HOSTLIST - dns_init_local(); -#endif -} - -/** - * Initialize one of the DNS servers. - * - * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS - * @param dnsserver IP address of the DNS server to set - */ -void ICACHE_FLASH_ATTR -dns_setserver(u8_t numdns, ip_addr_t *dnsserver) -{ - if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) && - (dnsserver != NULL) && !ip_addr_isany(dnsserver)) { - dns_servers[numdns] = (*dnsserver); - } -} - -/** - * Obtain one of the currently configured DNS server. - * - * @param numdns the index of the DNS server - * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS - * server has not been configured. - */ -ip_addr_t ICACHE_FLASH_ATTR -dns_getserver(u8_t numdns) -{ - if (numdns < DNS_MAX_SERVERS) { - return dns_servers[numdns]; - } else { - return *IP_ADDR_ANY; - } -} - -/** - * The DNS resolver client timer - handle retries and timeouts and should - * be called every DNS_TMR_INTERVAL milliseconds (every second by default). - */ -void ICACHE_FLASH_ATTR -dns_tmr(void) -{ - if (dns_pcb != NULL) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n")); - dns_check_entries(); - } -} - -#if DNS_LOCAL_HOSTLIST -static void ICACHE_FLASH_ATTR -dns_init_local() -{ -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) - int i; - struct local_hostlist_entry *entry; - /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */ - struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT; - size_t namelen; - for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) { - struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; - LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL); - namelen = os_strlen(init_entry->name); - LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); - entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); - LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); - if (entry != NULL) { - entry->name = (char*)entry + sizeof(struct local_hostlist_entry); - MEMCPY((char*)entry->name, init_entry->name, namelen); - ((char*)entry->name)[namelen] = 0; - entry->addr = init_entry->addr; - entry->next = local_hostlist_dynamic; - local_hostlist_dynamic = entry; - } - } -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */ -} - -/** - * Scans the local host-list for a hostname. - * - * @param hostname Hostname to look for in the local host-list - * @return The first IP address for the hostname in the local host-list or - * IPADDR_NONE if not found. - */ -static u32_t ICACHE_FLASH_ATTR -dns_lookup_local(const char *hostname) -{ -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC - struct local_hostlist_entry *entry = local_hostlist_dynamic; - while(entry != NULL) { - if(strcmp(entry->name, hostname) == 0) { - return ip4_addr_get_u32(&entry->addr); - } - entry = entry->next; - } -#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - int i; - for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) { - if(strcmp(local_hostlist_static[i].name, hostname) == 0) { - return ip4_addr_get_u32(&local_hostlist_static[i].addr); - } - } -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - return IPADDR_NONE; -} - -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC -/** Remove all entries from the local host-list for a specific hostname - * and/or IP addess - * - * @param hostname hostname for which entries shall be removed from the local - * host-list - * @param addr address for which entries shall be removed from the local host-list - * @return the number of removed entries - */ -int ICACHE_FLASH_ATTR -dns_local_removehost(const char *hostname, const ip_addr_t *addr) -{ - int removed = 0; - struct local_hostlist_entry *entry = local_hostlist_dynamic; - struct local_hostlist_entry *last_entry = NULL; - while (entry != NULL) { - if (((hostname == NULL) || !strcmp(entry->name, hostname)) && - ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) { - struct local_hostlist_entry *free_entry; - if (last_entry != NULL) { - last_entry->next = entry->next; - } else { - local_hostlist_dynamic = entry->next; - } - free_entry = entry; - entry = entry->next; - memp_free(MEMP_LOCALHOSTLIST, free_entry); - removed++; - } else { - last_entry = entry; - entry = entry->next; - } - } - return removed; -} - -/** - * Add a hostname/IP address pair to the local host-list. - * Duplicates are not checked. - * - * @param hostname hostname of the new entry - * @param addr IP address of the new entry - * @return ERR_OK if succeeded or ERR_MEM on memory error - */ -err_t ICACHE_FLASH_ATTR -dns_local_addhost(const char *hostname, const ip_addr_t *addr) -{ - struct local_hostlist_entry *entry; - size_t namelen; - LWIP_ASSERT("invalid host name (NULL)", hostname != NULL); - namelen = os_strlen(hostname); - LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); - entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); - if (entry == NULL) { - return ERR_MEM; - } - entry->name = (char*)entry + sizeof(struct local_hostlist_entry); - MEMCPY((char*)entry->name, hostname, namelen); - ((char*)entry->name)[namelen] = 0; - ip_addr_copy(entry->addr, *addr); - entry->next = local_hostlist_dynamic; - local_hostlist_dynamic = entry; - return ERR_OK; -} -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/ -#endif /* DNS_LOCAL_HOSTLIST */ - -/** - * Look up a hostname in the array of known hostnames. - * - * @note This function only looks in the internal array of known - * hostnames, it does not send out a query for the hostname if none - * was found. The function dns_enqueue() can be used to send a query - * for a hostname. - * - * @param name the hostname to look up - * @return the hostname's IP address, as u32_t (instead of ip_addr_t to - * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname - * was not found in the cached dns_table. - */ -static u32_t ICACHE_FLASH_ATTR -dns_lookup(const char *name) -{ - u8_t i; -#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) - u32_t addr; -#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */ -#if DNS_LOCAL_HOSTLIST - if ((addr = dns_lookup_local(name)) != IPADDR_NONE) { - return addr; - } -#endif /* DNS_LOCAL_HOSTLIST */ -#ifdef DNS_LOOKUP_LOCAL_EXTERN - if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) { - return addr; - } -#endif /* DNS_LOOKUP_LOCAL_EXTERN */ - - /* Walk through name list, return entry if found. If not, return NULL. */ - for (i = 0; i < DNS_TABLE_SIZE; ++i) { - if ((dns_table[i].state == DNS_STATE_DONE) && - (strcmp(name, dns_table[i].name) == 0)) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); - ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr)); - LWIP_DEBUGF(DNS_DEBUG, ("\n")); - return ip4_addr_get_u32(&dns_table[i].ipaddr); - } - } - - return IPADDR_NONE; -} - -#if DNS_DOES_NAME_CHECK -/** - * Compare the "dotted" name "query" with the encoded name "response" - * to make sure an answer from the DNS server matches the current dns_table - * entry (otherwise, answers might arrive late for hostname not on the list - * any more). - * - * @param query hostname (not encoded) from the dns_table - * @param response encoded hostname in the DNS response - * @return 0: names equal; 1: names differ - */ -static u8_t ICACHE_FLASH_ATTR -dns_compare_name(unsigned char *query, unsigned char *response) -{ - unsigned char n; - - do { - n = *response++; - /** @see RFC 1035 - 4.1.4. Message compression */ - if ((n & 0xc0) == 0xc0) { - /* Compressed name */ - break; - } else { - /* Not compressed name */ - while (n > 0) { - if ((*query) != (*response)) { - return 1; - } - ++response; - ++query; - --n; - }; - ++query; - } - } while (*response != 0); - - return 0; -} -#endif /* DNS_DOES_NAME_CHECK */ - -/** - * Walk through a compact encoded DNS name and return the end of the name. - * - * @param query encoded DNS name in the DNS server response - * @return end of the name - */ -static unsigned char * ICACHE_FLASH_ATTR -dns_parse_name(unsigned char *query) -{ - unsigned char n; - - do { - n = *query++; - /** @see RFC 1035 - 4.1.4. Message compression */ - if ((n & 0xc0) == 0xc0) { - /* Compressed name */ - break; - } else { - /* Not compressed name */ - while (n > 0) { - ++query; - --n; - }; - } - } while (*query != 0); - - return query + 1; -} - -/** - * Send a DNS query packet. - * - * @param numdns index of the DNS server in the dns_servers table - * @param name hostname to query - * @param id index of the hostname in dns_table, used as transaction ID in the - * DNS query packet - * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise - */ -static err_t ICACHE_FLASH_ATTR -dns_send(u8_t numdns, const char* name, u8_t id) -{ - err_t err; - struct dns_hdr *hdr; - struct dns_query qry; - struct pbuf *p; - char *query, *nptr; - const char *pHostname; - u8_t n; - dns_random = os_random()>>16; - LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", - (u16_t)(numdns), name)); - LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS); - LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns])); - - /* if here, we have either a new query or a retry on a previous query to process */ - p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH + - SIZEOF_DNS_QUERY, PBUF_RAM); - if (p != NULL) { - LWIP_ASSERT("pbuf must be in one piece", p->next == NULL); - /* fill dns header */ - hdr = (struct dns_hdr*)p->payload; - os_memset(hdr, 0, SIZEOF_DNS_HDR); - hdr->id = htons(id + dns_random); - hdr->flags1 = DNS_FLAG1_RD; - hdr->numquestions = PP_HTONS(1); - query = (char*)hdr + SIZEOF_DNS_HDR; - pHostname = name; - --pHostname; - - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while(*pHostname != 0); - *query++='\0'; - - /* fill dns query */ - qry.type = PP_HTONS(DNS_RRTYPE_A); - qry.cls = PP_HTONS(DNS_RRCLASS_IN); - SMEMCPY(query, &qry, SIZEOF_DNS_QUERY); - - /* resize pbuf to the exact dns query */ - pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload)))); - - /* connect to the server for faster receiving */ - udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT); - /* send dns packet */ - err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT); - - /* free pbuf */ - pbuf_free(p); - } else { - err = ERR_MEM; - } - - return err; -} - -/** - * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query. - * Check an entry in the dns_table: - * - send out query for new entries - * - retry old pending entries on timeout (also with different servers) - * - remove completed entries from the table if their TTL has expired - * - * @param i index of the dns_table entry to check - */ -static void ICACHE_FLASH_ATTR -dns_check_entry(u8_t i) -{ - err_t err; - struct dns_table_entry *pEntry = &dns_table[i]; - - LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); - - switch(pEntry->state) { - - case DNS_STATE_NEW: { - /* initialize new entry */ - pEntry->state = DNS_STATE_ASKING; - pEntry->numdns = 0; - pEntry->tmr = 1; - pEntry->retries = 0; - - /* send DNS packet for this entry */ - err = dns_send(pEntry->numdns, pEntry->name, i); - if (err != ERR_OK) { - LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, - ("dns_send returned error: %s\n", lwip_strerr(err))); - } - break; - } - - case DNS_STATE_ASKING: { - if (--pEntry->tmr == 0) { - if (++pEntry->retries == DNS_MAX_RETRIES) { - if ((pEntry->numdns+1numdns+1])) { - /* change of server */ - pEntry->numdns++; - pEntry->tmr = 1; - pEntry->retries = 0; - break; - } else { - LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name)); - /* call specified callback function if provided */ - if (pEntry->found) - (*pEntry->found)(pEntry->name, NULL, pEntry->arg); - /* flush this entry */ - pEntry->state = DNS_STATE_UNUSED; - pEntry->found = NULL; - break; - } - } - - /* wait longer for the next retry */ - pEntry->tmr = pEntry->retries; - - /* send DNS packet for this entry */ - err = dns_send(pEntry->numdns, pEntry->name, i); - if (err != ERR_OK) { - LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, - ("dns_send returned error: %s\n", lwip_strerr(err))); - } - } - break; - } - - case DNS_STATE_DONE: { - /* if the time to live is nul */ - if ((pEntry->ttl == 0) || (--pEntry->ttl == 0)) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name)); - /* flush this entry */ - pEntry->state = DNS_STATE_UNUSED; - pEntry->found = NULL; - } - break; - } - case DNS_STATE_UNUSED: - /* nothing to do */ - break; - default: - LWIP_ASSERT("unknown dns_table entry state:", 0); - break; - } -} - -/** - * Call dns_check_entry for each entry in dns_table - check all entries. - */ -static void ICACHE_FLASH_ATTR -dns_check_entries(void) -{ - u8_t i; - - for (i = 0; i < DNS_TABLE_SIZE; ++i) { - dns_check_entry(i); - } -} - -/** - * Receive input function for DNS response packets arriving for the dns UDP pcb. - * - * @params see udp.h - */ -static void ICACHE_FLASH_ATTR -dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) -{ - u16_t i; - char *pHostname; - struct dns_hdr *hdr; - struct dns_answer ans; - struct dns_table_entry *pEntry; - u16_t nquestions, nanswers; - - u8_t* dns_payload_buffer = (u8_t* )os_zalloc(LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)); - dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer); - - LWIP_UNUSED_ARG(arg); - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(addr); - LWIP_UNUSED_ARG(port); - - /* is the dns message too big ? */ - if (p->tot_len > DNS_MSG_SIZE) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n")); - /* free pbuf and return */ - goto memerr; - } - - /* is the dns message big enough ? */ - if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); - /* free pbuf and return */ - goto memerr; - } - - /* copy dns payload inside static buffer for processing */ - if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) { - /* The ID in the DNS header should be our entry into the name table. */ - hdr = (struct dns_hdr*)dns_payload; - i = htons(hdr->id); - i = i - dns_random; - if (i < DNS_TABLE_SIZE) { - pEntry = &dns_table[i]; - if(pEntry->state == DNS_STATE_ASKING) { - pEntry->err = hdr->flags2 & DNS_FLAG2_ERR_MASK; - - /* We only care about the question(s) and the answers. The authrr - and the extrarr are simply discarded. */ - nquestions = htons(hdr->numquestions); - nanswers = htons(hdr->numanswers); - - /* Check for error. If so, call callback to inform. */ - if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name)); - /* call callback to indicate error, clean up memory and return */ - //goto responseerr; - goto memerr; - } - /* This entry is now completed. */ - pEntry->state = DNS_STATE_DONE; - -#if DNS_DOES_NAME_CHECK - /* Check if the name in the "question" part match with the name in the entry. */ - if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name)); - /* call callback to indicate error, clean up memory and return */ - goto responseerr; - } -#endif /* DNS_DOES_NAME_CHECK */ - - /* Skip the name in the "question" part */ - pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY; - - while (nanswers > 0) { - /* skip answer resource record's host name */ - pHostname = (char *) dns_parse_name((unsigned char *)pHostname); - - /* Check for IP address type and Internet class. Others are discarded. */ - SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER); - if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) && - (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) { - /* read the answer resource record's TTL, and maximize it if needed */ - pEntry->ttl = ntohl(ans.ttl); - if (pEntry->ttl > DNS_MAX_TTL) { - pEntry->ttl = DNS_MAX_TTL; - } - /* read the IP address after answer resource record's header */ - SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t)); - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name)); - ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr))); - LWIP_DEBUGF(DNS_DEBUG, ("\n")); - /* call specified callback function if provided */ - if (pEntry->found) { - (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg); - } - if (pEntry->ttl == 0) { - /* RFC 883, page 29: "Zero values are - interpreted to mean that the RR can only be used for the - transaction in progress, and should not be cached." - -> flush this entry now */ - goto flushentry; - } - /* deallocate memory and return */ - goto memerr; - } else { - pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len); - } - --nanswers; - } - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name)); - /* call callback to indicate error, clean up memory and return */ - goto responseerr; - } - } - } - - /* deallocate memory and return */ - goto memerr; - -responseerr: - /* ERROR: call specified callback function with NULL as name to indicate an error */ - if (pEntry->found) { - (*pEntry->found)(pEntry->name, NULL, pEntry->arg); - } -flushentry: - /* flush this entry */ - pEntry->state = DNS_STATE_UNUSED; - pEntry->found = NULL; - -memerr: - /* free pbuf */ - pbuf_free(p); - os_free(dns_payload_buffer); - return; -} - -/** - * Queues a new hostname to resolve and sends out a DNS query for that hostname - * - * @param name the hostname that is to be queried - * @param found a callback founction to be called on success, failure or timeout - * @param callback_arg argument to pass to the callback function - * @return @return a err_t return code. - */ -static err_t ICACHE_FLASH_ATTR -dns_enqueue(const char *name, dns_found_callback found, void *callback_arg) -{ - u8_t i; - u8_t lseq, lseqi; - struct dns_table_entry *pEntry = NULL; - size_t namelen; - - /* search an unused entry, or the oldest one */ - lseq = lseqi = 0; - for (i = 0; i < DNS_TABLE_SIZE; ++i) { - pEntry = &dns_table[i]; - /* is it an unused entry ? */ - if (pEntry->state == DNS_STATE_UNUSED) - break; - - /* check if this is the oldest completed entry */ - if (pEntry->state == DNS_STATE_DONE) { - if ((dns_seqno - pEntry->seqno) > lseq) { - lseq = dns_seqno - pEntry->seqno; - lseqi = i; - } - } - } - - /* if we don't have found an unused entry, use the oldest completed one */ - if (i == DNS_TABLE_SIZE) { - if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) { - /* no entry can't be used now, table is full */ - LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name)); - return ERR_MEM; - } else { - /* use the oldest completed one */ - i = lseqi; - pEntry = &dns_table[i]; - } - } - - /* use this entry */ - LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i))); - - /* fill the entry */ - pEntry->state = DNS_STATE_NEW; - pEntry->seqno = dns_seqno++; - pEntry->found = found; - pEntry->arg = callback_arg; - namelen = LWIP_MIN(os_strlen(name), DNS_MAX_NAME_LENGTH-1); - MEMCPY(pEntry->name, name, namelen); - pEntry->name[namelen] = 0; - - /* force to send query without waiting timer */ - dns_check_entry(i); - - /* dns query is enqueued */ - return ERR_INPROGRESS; -} - -/** - * Resolve a hostname (string) into an IP address. - * NON-BLOCKING callback version for use with raw API!!! - * - * Returns immediately with one of err_t return codes: - * - ERR_OK if hostname is a valid IP address string or the host - * name is already in the local names table. - * - ERR_INPROGRESS enqueue a request to be sent to the DNS server - * for resolution if no errors are present. - * - ERR_ARG: dns client not initialized or invalid hostname - * - * @param hostname the hostname that is to be queried - * @param addr pointer to a ip_addr_t where to store the address if it is already - * cached in the dns_table (only valid if ERR_OK is returned!) - * @param found a callback function to be called on success, failure or timeout (only if - * ERR_INPROGRESS is returned!) - * @param callback_arg argument to pass to the callback function - * @return a err_t return code. - */ -err_t ICACHE_FLASH_ATTR -dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, - void *callback_arg) -{ - u32_t ipaddr; - /* not initialized or no valid server yet, or invalid addr pointer - * or invalid hostname or invalid hostname length */ - if ((dns_pcb == NULL) || (addr == NULL) || - (!hostname) || (!hostname[0]) || - (os_strlen(hostname) >= DNS_MAX_NAME_LENGTH)) { - return ERR_ARG; - } - -#if LWIP_HAVE_LOOPIF - if (strcmp(hostname, "localhost")==0) { - ip_addr_set_loopback(addr); - return ERR_OK; - } -#endif /* LWIP_HAVE_LOOPIF */ - - /* host name already in octet notation? set ip addr and return ERR_OK */ - ipaddr = ipaddr_addr(hostname); - if (ipaddr == IPADDR_NONE) { - /* already have this address cached? */ -// ipaddr = dns_lookup(hostname); - } - if (ipaddr != IPADDR_NONE) { - ip4_addr_set_u32(addr, ipaddr); - return ERR_OK; - } - - /* queue query with specified callback */ - return dns_enqueue(hostname, found, callback_arg); -} - -#endif /* LWIP_DNS */ diff --git a/tools/sdk/lwip/src/core/init.c b/tools/sdk/lwip/src/core/init.c deleted file mode 100644 index aa403f482..000000000 --- a/tools/sdk/lwip/src/core/init.c +++ /dev/null @@ -1,325 +0,0 @@ -/** - * @file - * Modules initialization - * - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" - -#include "lwip/init.h" -#include "lwip/stats.h" -#include "lwip/sys.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/pbuf.h" -#include "lwip/netif.h" -#include "lwip/sockets.h" -#include "lwip/ip.h" -#include "lwip/raw.h" -#include "lwip/udp.h" -#include "lwip/tcp_impl.h" -#include "lwip/snmp_msg.h" -#include "lwip/autoip.h" -#include "lwip/igmp.h" -#include "lwip/dns.h" -#include "lwip/timers.h" -#include "netif/etharp.h" - -/* Compile-time sanity checks for configuration errors. - * These can be done independently of LWIP_DEBUG, without penalty. - */ -#ifndef BYTE_ORDER - #error "BYTE_ORDER is not defined, you have to define it in your cc.h" -#endif -#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) - #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" -#endif -#if (!LWIP_ARP && ARP_QUEUEING) - #error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h" -#endif -#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_IGMP) - #error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h" -#endif -#if (!LWIP_UDP && LWIP_SNMP) - #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h" -#endif -#if (!LWIP_UDP && LWIP_DNS) - #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" -#endif -#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0)) - #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h" -#endif -#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0)) - #error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h" -#endif -#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0)) - #error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h" -#endif -//#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0)) -// #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h" -//#endif -//#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" -//#endif -#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff)) - #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h" -#endif -#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2)) - #error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work" -#endif -//#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12))) -// #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h" -//#endif -#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_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_NETIF_API && (NO_SYS==1)) - #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h" -#endif -#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_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 -#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" -#endif -#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK) - #error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h" -#endif -#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 -/* 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)) - #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 -#if (MEM_LIBC_MALLOC && MEM_USE_POOLS) - #error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h" -#endif -#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS) - #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h" -#endif -#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT) - #error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf" -#endif -#if (TCP_QUEUE_OOSEQ && !LWIP_TCP) - #error "TCP_QUEUE_OOSEQ requires LWIP_TCP" -#endif -#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT))) - #error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST" -#endif -#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT - #error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on" -#endif -#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT) - #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT" -#endif -#if LWIP_IGMP && !defined(LWIP_RAND) - #error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value" -#endif -#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING - #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too" -#endif -#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE - #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets" -#endif -#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF - #error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues" -#endif - - -/* Compile-time checks for deprecated options. - */ -#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 -#ifdef RAW_STATS - #error "RAW_STATS option is deprecated. Remove it from your lwipopts.h." -#endif -#ifdef ETHARP_QUEUE_FIRST - #error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h." -#endif -#ifdef ETHARP_ALWAYS_INSERT - #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h." -#endif - -#ifdef LWIP_DEBUG -static void ICACHE_FLASH_ATTR -lwip_sanity_check(void) -{ - /* Warnings */ -#if LWIP_NETCONN - if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB)) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n")); -#endif /* LWIP_NETCONN */ -#if LWIP_TCP - if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n")); - if (TCP_SND_BUF < 2 * TCP_MSS) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n")); - if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS))) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n")); - if (TCP_SNDLOWAT >= TCP_SND_BUF) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\n")); - if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\n")); - if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE)) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n")); - if (TCP_WND < TCP_MSS) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n")); -#endif /* LWIP_TCP */ -#if LWIP_SOCKET - /* Check that the SO_* socket options and SOF_* lwIP-internal flags match */ - if (SO_ACCEPTCONN != SOF_ACCEPTCONN) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n")); - if (SO_REUSEADDR != SOF_REUSEADDR) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n")); - if (SO_KEEPALIVE != SOF_KEEPALIVE) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n")); - if (SO_BROADCAST != SOF_BROADCAST) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n")); - if (SO_LINGER != SOF_LINGER) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n")); -#endif /* LWIP_SOCKET */ -} -#else /* LWIP_DEBUG */ -#define lwip_sanity_check() -#endif /* LWIP_DEBUG */ - -/** - * Perform Sanity check of user-configurable values, and initialize all modules. - */ -void -lwip_init(void) -{ - MEMP_NUM_TCP_PCB = 5; - TCP_WND = (4 * TCP_MSS); - TCP_MAXRTX = 12; - TCP_SYNMAXRTX = 6; - - /* Sanity check user-configurable values */ - lwip_sanity_check(); - - /* Modules initialization */ - stats_init(); -#if !NO_SYS - sys_init(); -#endif /* !NO_SYS */ -#if 0 - mem_init(&_bss_end); -#endif - memp_init(); - - pbuf_init(); - - netif_init(); - -#if LWIP_SOCKET - lwip_socket_init(); -#endif /* LWIP_SOCKET */ - ip_init(); - -#if LWIP_ARP - etharp_init(); - -#endif /* LWIP_ARP */ -#if LWIP_RAW - raw_init(); - -#endif /* LWIP_RAW */ -#if LWIP_UDP - udp_init(); - -#endif /* LWIP_UDP */ -#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 LWIP_TIMERS - sys_timeouts_init(); -#endif /* LWIP_TIMERS */ -} diff --git a/tools/sdk/lwip/src/core/ipv4/autoip.c b/tools/sdk/lwip/src/core/ipv4/autoip.c deleted file mode 100644 index cdba69d6b..000000000 --- a/tools/sdk/lwip/src/core/ipv4/autoip.c +++ /dev/null @@ -1,536 +0,0 @@ -/** - * @file - * AutoIP Automatic LinkLocal IP Configuration - * - */ - -/* - * - * Copyright (c) 2007 Dominik Spies - * 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: Dominik Spies - * - * 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 - * - */ - -/******************************************************************************* - * 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_AUTOIP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/mem.h" -#include "lwip/udp.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/autoip.h" -#include "netif/etharp.h" - -#include -#include - -/* 169.254.0.0 */ -#define AUTOIP_NET 0xA9FE0000 -/* 169.254.1.0 */ -#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100) -/* 169.254.254.255 */ -#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF) - - -/** Pseudo random macro based on netif informations. - * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */ -#ifndef LWIP_AUTOIP_RAND -#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \ - ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \ - ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \ - ((u32_t)((netif->hwaddr[4]) & 0xff))) + \ - (netif->autoip?netif->autoip->tried_llipaddr:0)) -#endif /* LWIP_AUTOIP_RAND */ - -/** - * Macro that generates the initial IP address to be tried by AUTOIP. - * If you want to override this, define it to something else in lwipopts.h. - */ -#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR -#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \ - htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \ - ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8))) -#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */ - -/* static functions */ -static void autoip_handle_arp_conflict(struct netif *netif); - -/* creates 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); - -/** - * Initialize this module - */ -void -autoip_init(void) -{ - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n")); -} - -/** Set a statically allocated struct autoip to work with. - * Using this prevents autoip_start to allocate it using mem_malloc. - * - * @param netif the netif for which to set the struct autoip - * @param dhcp (uninitialised) dhcp struct allocated by the application - */ -void -autoip_set_struct(struct netif *netif, struct autoip *autoip) -{ - LWIP_ASSERT("netif != NULL", netif != NULL); - LWIP_ASSERT("autoip != NULL", autoip != NULL); - LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL); - - /* clear data structure */ - os_memset(autoip, 0, sizeof(struct autoip)); - /* autoip->state = AUTOIP_STATE_OFF; */ - netif->autoip = autoip; -} - -/** Restart AutoIP client and check the next address (conflict detected) - * - * @param netif The netif under AutoIP control - */ -static void -autoip_restart(struct netif *netif) -{ - netif->autoip->tried_llipaddr++; - autoip_start(netif); -} - -/** - * Handle a IP address conflict after an ARP conflict detection - */ -static void -autoip_handle_arp_conflict(struct netif *netif) -{ - /* Somehow detect if we are defending or retreating */ - unsigned char defend = 1; /* tbd */ - - if(defend) { - if(netif->autoip->lastconflict > 0) { - /* 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")); - - /* 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 do not defend, retreating\n")); - /* TODO: close all TCP sessions */ - autoip_restart(netif); - } -} - -/** - * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255 - * - * @param netif network interface on which create the IP-Address - * @param ipaddr ip address to initialize - */ -static void -autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr) -{ - /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 - * compliant to RFC 3927 Section 2.1 - * We have 254 * 256 possibilities */ - - u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); - addr += netif->autoip->tried_llipaddr; - addr = AUTOIP_NET | (addr & 0xffff); - /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ - - if (addr < AUTOIP_RANGE_START) { - addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; - } - if (addr > AUTOIP_RANGE_END) { - addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; - } - LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) && - (addr <= AUTOIP_RANGE_END)); - ip4_addr_set_u32(ipaddr, htonl(addr)); - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - (u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), - ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); -} - -/** - * Sends an ARP probe from a network interface - * - * @param netif network interface used to send the probe - */ -static err_t -autoip_arp_probe(struct netif *netif) -{ - return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, - (struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, ðzero, - &netif->autoip->llipaddr, ARP_REQUEST); -} - -/** - * Sends an ARP announce from a network interface - * - * @param netif network interface used to send the announce - */ -static err_t -autoip_arp_announce(struct netif *netif) -{ - return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, - (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, ðzero, - &netif->autoip->llipaddr, ARP_REQUEST); -} - -/** - * Configure interface for use with current LL IP-Address - * - * @param netif network interface to configure with current LL IP-Address - */ -static err_t -autoip_bind(struct netif *netif) -{ - 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", - (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, - ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), - ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); - - IP4_ADDR(&sn_mask, 255, 255, 0, 0); - IP4_ADDR(&gw_addr, 0, 0, 0, 0); - - 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; -} - -/** - * Start AutoIP client - * - * @param netif network interface on which start the AutoIP client - */ -err_t -autoip_start(struct netif *netif) -{ - struct autoip *autoip = netif->autoip; - err_t result = ERR_OK; - - 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 - */ - ip_addr_set_zero(&netif->ip_addr); - ip_addr_set_zero(&netif->netmask); - ip_addr_set_zero(&netif->gw); - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], - netif->name[1], (u16_t)netif->num)); - if(autoip == NULL) { - /* no AutoIP client attached yet? */ - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_start(): starting new AUTOIP client\n")); - autoip = (struct autoip *)mem_malloc(sizeof(struct autoip)); - if(autoip == NULL) { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_start(): could not allocate autoip\n")); - return ERR_MEM; - } - os_memset(autoip, 0, sizeof(struct autoip)); - /* store this AutoIP client in the netif */ - netif->autoip = autoip; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); - } else { - autoip->state = AUTOIP_STATE_OFF; - autoip->ttw = 0; - autoip->sent_num = 0; - ip_addr_set_zero(&autoip->llipaddr); - autoip->lastconflict = 0; - } - - autoip_create_addr(netif, &(autoip->llipaddr)); - autoip_start_probing(netif); - - return result; -} - -static void -autoip_start_probing(struct netif *netif) -{ - struct autoip *autoip = netif->autoip; - - autoip->state = AUTOIP_STATE_PROBING; - autoip->sent_num = 0; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), - ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); - - /* time to wait to first probe, this is randomly - * choosen out of 0 to PROBE_WAIT seconds. - * 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 - * accquiring and probing address - * compliant to RFC 3927 Section 2.2.1 - */ - if(autoip->tried_llipaddr > MAX_CONFLICTS) { - autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND; - } -} - -/** - * Handle a possible change in the network configuration. - * - * If there is an AutoIP address configured, take the interface down - * and begin probing with the same address. - */ -void -autoip_network_changed(struct netif *netif) -{ - if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) { - netif_set_down(netif); - autoip_start_probing(netif); - } -} - -/** - * Stop AutoIP client - * - * @param netif network interface on which stop the AutoIP client - */ -err_t -autoip_stop(struct netif *netif) -{ - netif->autoip->state = AUTOIP_STATE_OFF; - netif_set_down(netif); - return ERR_OK; -} - -/** - * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds - */ -void -autoip_tmr() -{ - struct netif *netif = netif_list; - /* loop through netif's */ - while (netif != NULL) { - /* only act on AutoIP configured interfaces */ - 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)(netif->autoip->state), netif->autoip->ttw)); - - switch(netif->autoip->state) { - case AUTOIP_STATE_PROBING: - 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(&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")); - 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(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(netif->autoip->sent_num >= ANNOUNCE_NUM) { - netif->autoip->state = AUTOIP_STATE_BOUND; - netif->autoip->sent_num = 0; - netif->autoip->ttw = 0; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), - ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); - } - } - break; - } - } - /* proceed to next network interface */ - netif = netif->next; - } -} - -/** - * Handles every incoming ARP Packet, called by etharp_arp_input. - * - * @param netif network interface to use for autoip processing - * @param hdr Incoming ARP packet - */ -void -autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) -{ - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n")); - if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) { - /* when ip.src == llipaddr && hw.src != netif->hwaddr - * - * when probing ip.dst == llipaddr && hw.src != netif->hwaddr - * we have a conflict and must solve it - */ - ip_addr_t sipaddr, dipaddr; - struct eth_addr netifaddr; - ETHADDR16_COPY(netifaddr.addr, netif->hwaddr); - - /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without - * structure packing (not using structure copy which breaks strict-aliasing rules). - */ - IPADDR2_COPY(&sipaddr, &hdr->sipaddr); - IPADDR2_COPY(&dipaddr, &hdr->dipaddr); - - 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 ((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")); - autoip_restart(netif); - } - } else { - /* RFC 3927 Section 2.5: - * in any state we have a conflict if - * ip.src == llipaddr && hw.src != own hwaddr - */ - 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")); - autoip_handle_arp_conflict(netif); - } - } - } -} - -#endif /* LWIP_AUTOIP */ diff --git a/tools/sdk/lwip/src/core/ipv4/icmp.c b/tools/sdk/lwip/src/core/ipv4/icmp.c deleted file mode 100644 index 2eb3b02cc..000000000 --- a/tools/sdk/lwip/src/core/ipv4/icmp.c +++ /dev/null @@ -1,338 +0,0 @@ -/** - * @file - * ICMP - Internet Control Message Protocol - * - */ - -/* - * 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 - * - */ - -/* Some ICMP messages should be passed to the transport protocols. This - is not implemented. */ - -#include "lwip/opt.h" - -#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/icmp.h" -#include "lwip/inet_chksum.h" -#include "lwip/ip.h" -#include "lwip/def.h" -#include "lwipopts.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" - -#include - -/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be - * used to modify and send a response packet (and to 1 if this is not the case, - * e.g. when link header is stripped of when receiving) */ -#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN -#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1 -#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ - -/* The amount of data from the original packet to return in a dest-unreachable */ -#define ICMP_DEST_UNREACH_DATASIZE 8 - -static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code); - -/** - * Processes ICMP input packets, called from ip_input(). - * - * Currently only processes icmp echo requests and sends - * out the echo response. - * - * @param p the icmp echo request packet, p->payload pointing to the ip header - * @param inp the netif on which this packet was received - */ -void -icmp_input(struct pbuf *p, struct netif *inp) -{ - u8_t type; -#ifdef LWIP_DEBUG - u8_t code; -#endif /* LWIP_DEBUG */ - struct icmp_echo_hdr *iecho; - struct ip_hdr *iphdr; - s16_t hlen; - - ICMP_STATS_INC(icmp.recv); - snmp_inc_icmpinmsgs(); - - - 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; - } - - type = *((u8_t *)p->payload); -#ifdef LWIP_DEBUG - code = *(((u8_t *)p->payload)+1); -#endif /* LWIP_DEBUG */ - switch (type) { - case ICMP_ER: - /* This is OK, echo reply might have been parsed by a raw PCB - (as obviously, an echo request has been sent, too). */ - break; - case ICMP_ECHO: -#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING - { - int accepted = 1; -#if !LWIP_MULTICAST_PING - /* multicast destination address? */ - if (ip_addr_ismulticast(¤t_iphdr_dest)) { - accepted = 0; - } -#endif /* LWIP_MULTICAST_PING */ -#if !LWIP_BROADCAST_PING - /* broadcast destination address? */ - if (ip_addr_isbroadcast(¤t_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 (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; - } -#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN - if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) { - /* p is not big enough to contain link headers - * allocate a new one and copy p into it - */ - 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, PBUF_RAM); - if (r == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); - goto memerr; - } - 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_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 */ - if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) { - LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); - goto memerr; - } - } -#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ - /* At this point, all checks are OK. */ - /* We generate an answer by switching the dest and src ip addresses, - * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ - iecho = (struct icmp_echo_hdr *)p->payload; - ip_addr_copy(iphdr->src, *ip_current_dest_addr()); - ip_addr_copy(iphdr->dest, *ip_current_src_addr()); - ICMPH_TYPE_SET(iecho, ICMP_ER); - /* adjust the checksum */ - if (iecho->chksum >= PP_HTONS(0xffff - (ICMP_ECHO << 8))) { - iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1; - } else { - iecho->chksum += PP_HTONS(ICMP_ECHO << 8); - } - - /* Set the correct TTL and recalculate the header checksum. */ - IPH_TTL_SET(iphdr, ICMP_TTL); - IPH_CHKSUM_SET(iphdr, 0); -#if CHECKSUM_GEN_IP - 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 */ - snmp_inc_icmpoutmsgs(); - /* increase number of echo replies attempted to send */ - snmp_inc_icmpoutechoreps(); - - 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: %c.\n", ret)); - } - } - break; - default: - 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); - } - pbuf_free(p); - return; -lenerr: - pbuf_free(p); - ICMP_STATS_INC(icmp.lenerr); - snmp_inc_icmpinerrors(); - return; -#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN -memerr: - pbuf_free(p); - ICMP_STATS_INC(icmp.err); - snmp_inc_icmpinerrors(); - return; -#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ -} - -/** - * Send an icmp 'destination unreachable' packet, called from ip_input() if - * the transport layer protocol is unknown and from udp_input() if the local - * port is not bound. - * - * @param p the input packet for which the 'unreachable' should be sent, - * p->payload pointing to the IP header - * @param t type of the 'unreachable' packet - */ -void -icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) -{ - icmp_send_response(p, ICMP_DUR, t); -} - -#if IP_FORWARD || IP_REASSEMBLY -/** - * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. - * - * @param p the input packet for which the 'time exceeded' should be sent, - * p->payload pointing to the IP header - * @param t type of the 'time exceeded' packet - */ -void -icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) -{ - icmp_send_response(p, ICMP_TE, t); -} - -#endif /* IP_FORWARD || IP_REASSEMBLY */ - -/** - * Send an icmp packet in response to an incoming packet. - * - * @param p the input packet for which the 'unreachable' should be sent, - * p->payload pointing to the IP header - * @param type Type of the ICMP header - * @param code Code of the ICMP header - */ -static void ICACHE_FLASH_ATTR -icmp_send_response(struct pbuf *p, u8_t type, u8_t code) -{ - struct pbuf *q; - struct ip_hdr *iphdr; - /* we can use the echo header here */ - struct icmp_echo_hdr *icmphdr; - ip_addr_t iphdr_src; - - /* ICMP header + IP header + 8 bytes of data */ - //Ϊ²î´í±¨ÎÄÉêÇëpbuf¿Õ¼ä£¬pbufÖÐÔ¤ÁôIPÊײ¿ºÍÒÔÌ«ÍøÊײ¿¿Õ¼ä£¬pbufÊý¾ÝÇø - //³¤¶È=²î´í±¨ÎÄÊײ¿+²î´í±¨ÎÄÊý¾Ý³¤¶È(IPÊײ¿³¤¶È+8) - q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, - PBUF_RAM); - if (q == NULL) {//ʧ°Ü£¬·µ»Ø - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); - return; - } - LWIP_ASSERT("check that first pbuf can hold icmp message", - (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); - - iphdr = (struct ip_hdr *)p->payload;//Ö¸ÏòÒýÆð²î´íµÄIPÊý¾Ý°üÊײ¿ - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); - ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); - LWIP_DEBUGF(ICMP_DEBUG, (" to ")); - ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); - LWIP_DEBUGF(ICMP_DEBUG, ("\n")); - - icmphdr = (struct icmp_echo_hdr *)q->payload;//Ö¸Ïò²î´í±¨ÎÄÊײ¿ - icmphdr->type = type;//ÌîдÀàÐÍ×Ö¶Î - icmphdr->code = code;//Ìîд´úÂë×Ö¶Î - icmphdr->id = 0;//¶ÔÓÚÄ¿µÄ²»¿É´ïºÍÊý¾Ý±¨³¬Ê± - icmphdr->seqno = 0;//±¨ÎÄ£¬Êײ¿Ê£ÓàµÄ4¸ö×Ö½Ú¶¼Îª0 - - /* copy fields from original packet ½«ÒýÆð²î´íµÄIPÊý¾Ý±¨µÄIPÊײ¿+8×Ö½ÚÊý¾Ý¿½±´µ½²î´í±¨ÎÄÊý¾ÝÇø*/ - SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, - IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); - - /* calculate checksum */ - icmphdr->chksum = 0;//±¨ÎÄУÑéºÍ×Ö¶ÎÇå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);//µ÷ÓÃIP²ãº¯ÊýÊä³öICMP±¨ÎÄ - pbuf_free(q); -} - -#endif /* LWIP_ICMP */ diff --git a/tools/sdk/lwip/src/core/ipv4/igmp.c b/tools/sdk/lwip/src/core/ipv4/igmp.c deleted file mode 100644 index 9c07fd6bc..000000000 --- a/tools/sdk/lwip/src/core/ipv4/igmp.c +++ /dev/null @@ -1,832 +0,0 @@ -/** - * @file - * IGMP - Internet Group Management Protocol - * - */ - -/* - * Copyright (c) 2002 CITEL 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. Neither the name of CITEL Technologies Ltd nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``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 CITEL TECHNOLOGIES OR CONTRIBUTORS 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 a contribution to the lwIP TCP/IP stack. - * The Swedish Institute of Computer Science and Adam Dunkels - * are specifically granted permission to redistribute this - * source code. -*/ - -/*------------------------------------------------------------- -Note 1) -Although the rfc requires V1 AND V2 capability -we will only support v2 since now V1 is very old (August 1989) -V1 can be added if required - -a debug print and statistic have been implemented to -show this up. -------------------------------------------------------------- -------------------------------------------------------------- -Note 2) -A query for a specific group address (as opposed to ALLHOSTS) -has now been implemented as I am unsure if it is required - -a debug print and statistic have been implemented to -show this up. -------------------------------------------------------------- -------------------------------------------------------------- -Note 3) -The router alert rfc 2113 is implemented in outgoing packets -but not checked rigorously incoming -------------------------------------------------------------- -Steve Reynolds -------------------------------------------------------------*/ - -/*----------------------------------------------------------------------------- - * RFC 988 - Host extensions for IP multicasting - V0 - * RFC 1054 - Host extensions for IP multicasting - - * RFC 1112 - Host extensions for IP multicasting - V1 - * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard) - * RFC 3376 - Internet Group Management Protocol, Version 3 - V3 - * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+ - * RFC 2113 - IP Router Alert Option - - *----------------------------------------------------------------------------*/ - -/*----------------------------------------------------------------------------- - * Includes - *----------------------------------------------------------------------------*/ - -#include "lwip/opt.h" - -#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/igmp.h" -#include "lwip/debug.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/ip.h" -#include "lwip/inet_chksum.h" -#include "lwip/netif.h" -#include "lwip/icmp.h" -#include "lwip/udp.h" -#include "lwip/tcp.h" -#include "lwip/stats.h" - -#include "string.h" - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -/* - * IGMP constants - */ -#define IGMP_TTL 1 -#define IGMP_MINLEN 8 -#define ROUTER_ALERT 0x9404 -#define ROUTER_ALERTLEN 4 - -/* - * IGMP message types, including version number. - */ -#define IGMP_MEMB_QUERY 0x11 /* Membership query */ -#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */ -#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */ -#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ - -/* Group membership states */ -#define IGMP_GROUP_NON_MEMBER 0 -#define IGMP_GROUP_DELAYING_MEMBER 1 -#define IGMP_GROUP_IDLE_MEMBER 2 - -/** - * IGMP packet format. - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct igmp_msg { - PACK_STRUCT_FIELD(u8_t igmp_msgtype); - PACK_STRUCT_FIELD(u8_t igmp_maxresp); - PACK_STRUCT_FIELD(u16_t igmp_checksum); - PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - - -static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)ICACHE_FLASH_ATTR; -static err_t igmp_remove_group(struct igmp_group *group)ICACHE_FLASH_ATTR; -static void igmp_timeout( struct igmp_group *group)ICACHE_FLASH_ATTR; -static void igmp_start_timer(struct igmp_group *group, u8_t max_time)ICACHE_FLASH_ATTR; -static void igmp_stop_timer(struct igmp_group *group)ICACHE_FLASH_ATTR; -static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp)ICACHE_FLASH_ATTR; -static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)ICACHE_FLASH_ATTR; -static void igmp_send(struct igmp_group *group, u8_t type)ICACHE_FLASH_ATTR; - - -static struct igmp_group* igmp_group_list = NULL; -static ip_addr_t allsystems; -static ip_addr_t allrouters; - - -/** - * Initialize the IGMP module - */ -void -igmp_init(void) -{ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n")); - - IP4_ADDR(&allsystems, 224, 0, 0, 1); - IP4_ADDR(&allrouters, 224, 0, 0, 2); -} - -#ifdef LWIP_DEBUG -/** - * Dump global IGMP groups list - */ -void -igmp_dump_group_list() -{ - struct igmp_group *group = igmp_group_list; - - while (group != NULL) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state))); - ip_addr_debug_print(IGMP_DEBUG, &group->group_address); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); - group = group->next; - } - LWIP_DEBUGF(IGMP_DEBUG, ("\n")); -} -#else -#define igmp_dump_group_list() -#endif /* LWIP_DEBUG */ - -/** - * Start IGMP processing on interface - * - * @param netif network interface on which start IGMP processing - */ -err_t -igmp_start(struct netif *netif) -{ - struct igmp_group* group; - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif)); - - group = igmp_lookup_group(netif, &allsystems); - - if (group != NULL) { - group->group_state = IGMP_GROUP_IDLE_MEMBER; - group->use++; - - /* Allow the igmp messages at the MAC level */ - if (netif->igmp_mac_filter != NULL) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); - ip_addr_debug_print(IGMP_DEBUG, &allsystems); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); - netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER); - } - - return ERR_OK; - } - - return ERR_MEM; -} - -/** - * Stop IGMP processing on interface - * - * @param netif network interface on which stop IGMP processing - */ -err_t -igmp_stop(struct netif *netif) -{ - struct igmp_group *group = igmp_group_list; - struct igmp_group *prev = NULL; - struct igmp_group *next; - - /* look for groups joined on this interface further down the list */ - while (group != NULL) { - next = group->next; - /* is it a group joined on this interface? */ - if (group->netif == netif) { - /* is it the first group of the list? */ - if (group == igmp_group_list) { - igmp_group_list = next; - } - /* is there a "previous" group defined? */ - if (prev != NULL) { - prev->next = next; - } - /* disable the group at the MAC level */ - if (netif->igmp_mac_filter != NULL) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); - ip_addr_debug_print(IGMP_DEBUG, &group->group_address); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); - netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER); - } - /* free group */ - memp_free(MEMP_IGMP_GROUP, group); - } else { - /* change the "previous" */ - prev = group; - } - /* move to "next" */ - group = next; - } - return ERR_OK; -} - -/** - * Report IGMP memberships for this interface - * - * @param netif network interface on which report IGMP memberships - */ -void -igmp_report_groups(struct netif *netif) -{ - struct igmp_group *group = igmp_group_list; - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif)); - - while (group != NULL) { - if (group->netif == netif) { - igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); - } - group = group->next; - } -} - -/** - * Search for a group in the global igmp_group_list - * - * @param ifp the network interface for which to look - * @param addr the group ip address to search for - * @return a struct igmp_group* if the group has been found, - * NULL if the group wasn't found. - */ -struct igmp_group * -igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr) -{ - struct igmp_group *group = igmp_group_list; - - while (group != NULL) { - if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) { - return group; - } - group = group->next; - } - - /* to be clearer, we return NULL here instead of - * 'group' (which is also NULL at this point). - */ - return NULL; -} - -/** - * Search for a specific igmp group and create a new one if not found- - * - * @param ifp the network interface for which to look - * @param addr the group ip address to search - * @return a struct igmp_group*, - * NULL on memory error. - */ -struct igmp_group * -igmp_lookup_group(struct netif *ifp, ip_addr_t *addr) -{ - struct igmp_group *group = igmp_group_list; - - /* Search if the group already exists */ - group = igmp_lookfor_group(ifp, addr); - if (group != NULL) { - /* Group already exists. */ - return group; - } - - /* Group doesn't exist yet, create a new one */ - group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP); - if (group != NULL) { - group->netif = ifp; - ip_addr_set(&(group->group_address), addr); - group->timer = 0; /* Not running */ - group->group_state = IGMP_GROUP_NON_MEMBER; - group->last_reporter_flag = 0; - group->use = 0; - group->next = igmp_group_list; - - igmp_group_list = group; - } - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to "))); - ip_addr_debug_print(IGMP_DEBUG, addr); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp)); - - return group; -} - -/** - * Remove a group in the global igmp_group_list - * - * @param group the group to remove from the global igmp_group_list - * @return ERR_OK if group was removed from the list, an err_t otherwise - */ -static err_t -igmp_remove_group(struct igmp_group *group) -{ - err_t err = ERR_OK; - - /* Is it the first group? */ - if (igmp_group_list == group) { - igmp_group_list = group->next; - } else { - /* look for group further down the list */ - struct igmp_group *tmpGroup; - for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { - if (tmpGroup->next == group) { - tmpGroup->next = group->next; - break; - } - } - /* Group not found in the global igmp_group_list */ - if (tmpGroup == NULL) - err = ERR_ARG; - } - /* free group */ - memp_free(MEMP_IGMP_GROUP, group); - - return err; -} - -/** - * Called from ip_input() if a new IGMP packet is received. - * - * @param p received igmp packet, p->payload pointing to the ip header - * @param inp network interface on which the packet was received - * @param dest destination ip address of the igmp packet - */ -void -igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest) -{ - struct ip_hdr * iphdr; - struct igmp_msg* igmp; - struct igmp_group* group; - struct igmp_group* groupref; - - IGMP_STATS_INC(igmp.recv); - - /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */ - iphdr = (struct ip_hdr *)p->payload; - if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) { - pbuf_free(p); - IGMP_STATS_INC(igmp.lenerr); - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n")); - return; - } - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from ")); - ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src)); - LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); - ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest)); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp)); - - /* Now calculate and check the checksum */ - igmp = (struct igmp_msg *)p->payload; - if (inet_chksum(igmp, p->len)) { - pbuf_free(p); - IGMP_STATS_INC(igmp.chkerr); - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n")); - return; - } - - /* Packet is ok so find an existing group */ - group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */ - - /* If group can be found or create... */ - if (!group) { - pbuf_free(p); - IGMP_STATS_INC(igmp.drop); - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n")); - return; - } - - /* NOW ACT ON THE INCOMING MESSAGE TYPE... */ - switch (igmp->igmp_msgtype) { - case IGMP_MEMB_QUERY: { - /* IGMP_MEMB_QUERY to the "all systems" address ? */ - if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) { - /* THIS IS THE GENERAL QUERY */ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); - - if (igmp->igmp_maxresp == 0) { - IGMP_STATS_INC(igmp.rx_v1); - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n")); - igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR; - } else { - IGMP_STATS_INC(igmp.rx_general); - } - - groupref = igmp_group_list; - while (groupref) { - /* Do not send messages on the all systems group address! */ - if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) { - igmp_delaying_member(groupref, igmp->igmp_maxresp); - } - groupref = groupref->next; - } - } else { - /* IGMP_MEMB_QUERY to a specific group ? */ - if (!ip_addr_isany(&igmp->igmp_group_address)) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); - ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address); - if (ip_addr_cmp(dest, &allsystems)) { - ip_addr_t groupaddr; - LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); - /* we first need to re-look for the group since we used dest last time */ - ip_addr_copy(groupaddr, igmp->igmp_group_address); - group = igmp_lookfor_group(inp, &groupaddr); - } else { - LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); - } - - if (group != NULL) { - IGMP_STATS_INC(igmp.rx_group); - igmp_delaying_member(group, igmp->igmp_maxresp); - } else { - IGMP_STATS_INC(igmp.drop); - } - } else { - IGMP_STATS_INC(igmp.proterr); - } - } - break; - } - case IGMP_V2_MEMB_REPORT: { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n")); - IGMP_STATS_INC(igmp.rx_report); - if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { - /* This is on a specific group we have already looked up */ - group->timer = 0; /* stopped */ - group->group_state = IGMP_GROUP_IDLE_MEMBER; - group->last_reporter_flag = 0; - } - break; - } - default: { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n", - igmp->igmp_msgtype, group->group_state, &group, group->netif)); - IGMP_STATS_INC(igmp.proterr); - break; - } - } - - pbuf_free(p); - return; -} - -/** - * Join a group on one network interface. - * - * @param ifaddr ip address of the network interface which should join a new group - * @param groupaddr the ip address of the group which to join - * @return ERR_OK if group was joined on the netif(s), an err_t otherwise - */ -err_t -igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr) -{ - err_t err = ERR_VAL; /* no matching interface */ - struct igmp_group *group; - struct netif *netif; - - /* make sure it is multicast address */ - LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); - LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); - - /* loop through netif's */ - netif = netif_list; - while (netif != NULL) { - /* Should we join this interface ? */ - if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { - /* find group or create a new one if not found */ - group = igmp_lookup_group(netif, groupaddr); - - if (group != NULL) { - /* This should create a new group, check the state to make sure */ - if (group->group_state != IGMP_GROUP_NON_MEMBER) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n")); - } else { - /* OK - it was new group */ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: ")); - ip_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, ("\n")); - - /* If first use of the group, allow the group at the MAC level */ - if ((group->use==0) && (netif->igmp_mac_filter != NULL)) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD ")); - ip_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); - netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER); - } - - IGMP_STATS_INC(igmp.tx_join); - igmp_send(group, IGMP_V2_MEMB_REPORT); - - igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); - - /* Need to work out where this timer comes from */ - group->group_state = IGMP_GROUP_DELAYING_MEMBER; - } - /* Increment group use */ - group->use++; - /* Join on this interface */ - err = ERR_OK; - } else { - /* Return an error even if some network interfaces are joined */ - /** @todo undo any other netif already joined */ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n")); - return ERR_MEM; - } - } - /* proceed to next network interface */ - netif = netif->next; - } - - return err; -} - -/** - * Leave a group on one network interface. - * - * @param ifaddr ip address of the network interface which should leave a group - * @param groupaddr the ip address of the group which to leave - * @return ERR_OK if group was left on the netif(s), an err_t otherwise - */ -err_t -igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr) -{ - err_t err = ERR_VAL; /* no matching interface */ - struct igmp_group *group; - struct netif *netif; - - /* make sure it is multicast address */ - LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); - LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); - - /* loop through netif's */ - netif = netif_list; - while (netif != NULL) { - /* Should we leave this interface ? */ - if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { - /* find group */ - group = igmp_lookfor_group(netif, groupaddr); - - if (group != NULL) { - /* Only send a leave if the flag is set according to the state diagram */ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: ")); - ip_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, ("\n")); - - /* If there is no other use of the group */ - if (group->use <= 1) { - /* If we are the last reporter for this group */ - if (group->last_reporter_flag) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n")); - IGMP_STATS_INC(igmp.tx_leave); - igmp_send(group, IGMP_LEAVE_GROUP); - } - - /* Disable the group at the MAC level */ - if (netif->igmp_mac_filter != NULL) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL ")); - ip_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); - netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER); - } - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: ")); - ip_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, ("\n")); - - /* Free the group */ - igmp_remove_group(group); - } else { - /* Decrement group use */ - group->use--; - } - /* Leave on this interface */ - err = ERR_OK; - } else { - /* It's not a fatal error on "leavegroup" */ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n")); - } - } - /* proceed to next network interface */ - netif = netif->next; - } - - return err; -} - -/** - * The igmp timer function (both for NO_SYS=1 and =0) - * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default). - */ -void -igmp_tmr(void) -{ - struct igmp_group *group = igmp_group_list; - - while (group != NULL) { - if (group->timer > 0) { - group->timer--; - if (group->timer == 0) { - igmp_timeout(group); - } - } - group = group->next; - } -} - -/** - * Called if a timeout for one group is reached. - * Sends a report for this group. - * - * @param group an igmp_group for which a timeout is reached - */ -static void -igmp_timeout(struct igmp_group *group) -{ - /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */ - if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); - ip_addr_debug_print(IGMP_DEBUG, &(group->group_address)); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); - - IGMP_STATS_INC(igmp.tx_report); - igmp_send(group, IGMP_V2_MEMB_REPORT); - } -} - -/** - * Start a timer for an igmp group - * - * @param group the igmp_group for which to start a timer - * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with - * every call to igmp_tmr()) - */ -static void -igmp_start_timer(struct igmp_group *group, u8_t max_time) -{ - /* ensure the input value is > 0 */ -#ifdef LWIP_RAND - if (max_time == 0) { - max_time = 1; - } - /* ensure the random value is > 0 */ - group->timer = (LWIP_RAND() % max_time); - if (group->timer == 0) { - group->timer = 1; - } -#else /* LWIP_RAND */ - /* ATTENTION: use this only if absolutely necessary! */ - group->timer = max_time / 2; - if (group->timer == 0) { - group->timer = 1; - } -#endif /* LWIP_RAND */ -} - -/** - * Stop a timer for an igmp_group - * - * @param group the igmp_group for which to stop the timer - */ -static void -igmp_stop_timer(struct igmp_group *group) -{ - group->timer = 0; -} - -/** - * Delaying membership report for a group if necessary - * - * @param group the igmp_group for which "delaying" membership report - * @param maxresp query delay - */ -static void -igmp_delaying_member(struct igmp_group *group, u8_t maxresp) -{ - if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || - ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && - ((group->timer == 0) || (maxresp < group->timer)))) { - igmp_start_timer(group, maxresp); - group->group_state = IGMP_GROUP_DELAYING_MEMBER; - } -} - - -/** - * Sends an IP packet on a network interface. This function constructs the IP header - * and calculates the IP header checksum. If the source IP address is NULL, - * the IP address of the outgoing network interface is filled in as source address. - * - * @param p the packet to send (p->payload points to the data, e.g. next - protocol header; if dest == IP_HDRINCL, p already includes an IP - header and p->payload points to that IP header) - * @param src the source IP address to send from (if src == IP_ADDR_ANY, the - * IP address of the netif used to send is used as source address) - * @param dest the destination IP address to send the packet to - * @param ttl the TTL value to be set in the IP header - * @param proto the PROTOCOL to be set in the IP header - * @param netif the netif on which to send this packet - * @return ERR_OK if the packet was sent OK - * ERR_BUF if p doesn't have enough space for IP/LINK headers - * returns errors returned by netif->output - */ -static err_t -igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif) -{ - /* This is the "router alert" option */ - u16_t ra[2]; - ra[0] = PP_HTONS(ROUTER_ALERT); - ra[1] = 0x0000; /* Router shall examine packet */ - IGMP_STATS_INC(igmp.xmit); - return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN); -} - -/** - * Send an igmp packet to a specific group. - * - * @param group the group to which to send the packet - * @param type the type of igmp packet to send - */ -static void -igmp_send(struct igmp_group *group, u8_t type) -{ - struct pbuf* p = NULL; - struct igmp_msg* igmp = NULL; - ip_addr_t src = *IP_ADDR_ANY; - ip_addr_t* dest = NULL; - - /* IP header + "router alert" option + IGMP header */ - p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM); - - if (p) { - igmp = (struct igmp_msg *)p->payload; - LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg", - (p->len >= sizeof(struct igmp_msg))); - ip_addr_copy(src, group->netif->ip_addr); - - if (type == IGMP_V2_MEMB_REPORT) { - dest = &(group->group_address); - ip_addr_copy(igmp->igmp_group_address, group->group_address); - group->last_reporter_flag = 1; /* Remember we were the last to report */ - } else { - if (type == IGMP_LEAVE_GROUP) { - dest = &allrouters; - ip_addr_copy(igmp->igmp_group_address, group->group_address); - } - } - - if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) { - igmp->igmp_msgtype = type; - igmp->igmp_maxresp = 0; - igmp->igmp_checksum = 0; - igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN); - - igmp_ip_output_if(p, &src, dest, group->netif); - } - - pbuf_free(p); - } else { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); - IGMP_STATS_INC(igmp.memerr); - } -} - -#endif /* LWIP_IGMP */ diff --git a/tools/sdk/lwip/src/core/ipv4/inet.c b/tools/sdk/lwip/src/core/ipv4/inet.c deleted file mode 100644 index e283a5766..000000000 --- a/tools/sdk/lwip/src/core/ipv4/inet.c +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file - * 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: - * - * 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 - * - */ - -#include "lwip/opt.h" - -#include "lwip/inet.h" - diff --git a/tools/sdk/lwip/src/core/ipv4/inet_chksum.c b/tools/sdk/lwip/src/core/ipv4/inet_chksum.c deleted file mode 100644 index bfcc40d5b..000000000 --- a/tools/sdk/lwip/src/core/ipv4/inet_chksum.c +++ /dev/null @@ -1,450 +0,0 @@ -/** - * @file - * Incluse internet checksum 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: - * - * 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 - * - */ - -#include "lwip/opt.h" - -#include "lwip/inet_chksum.h" -#include "lwip/def.h" - -#include -#include - -/* 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 - * - * 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 -#endif -/* If none set: */ -#ifndef LWIP_CHKSUM_ALGORITHM -# define LWIP_CHKSUM_ALGORITHM 0 -#endif - -#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */ -/** - * lwip checksum - * - * @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) - * - * @note accumulator size limits summable length to 64k - * @note host endianess is irrelevant (p3 RFC1071) - */ -static u16_t ICACHE_FLASH_ATTR -lwip_standard_chksum(void *dataptr, u16_t len) -{ - u32_t acc; - u16_t src; - u8_t *octetptr; - - acc = 0; - /* dataptr may be at odd or even addresses */ - octetptr = (u8_t*)dataptr; - while (len > 1) { - /* declare first octet as most significant - thus assume network order, ignoring host order */ - src = (*octetptr) << 8; - octetptr++; - /* declare second octet as least significant */ - src |= (*octetptr); - octetptr++; - acc += src; - len -= 2; - } - if (len > 0) { - /* accumulate remaining octet */ - src = (*octetptr) << 8; - acc += src; - } - /* add deferred carry bits */ - acc = (acc >> 16) + (acc & 0x0000ffffUL); - if ((acc & 0xffff0000UL) != 0) { - acc = (acc >> 16) + (acc & 0x0000ffffUL); - } - /* 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 htons((u16_t)acc); -} -#endif - -#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */ -/* - * Curt McDowell - * Broadcom Corp. - * csm@broadcom.com - * - * IP checksum two bytes at a time with support for - * unaligned buffer. - * Works for len up to and including 0x20000. - * by Curt McDowell, Broadcom Corp. 12/08/2005 - * - * @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) - */ - -static u16_t ICACHE_FLASH_ATTR -lwip_standard_chksum(void *dataptr, int len) -{ - u8_t *pb = (u8_t *)dataptr; - u16_t *ps, t = 0; - u32_t sum = 0; - int odd = ((mem_ptr_t)pb & 1); - - /* Get aligned to u16_t */ - if (odd && len > 0) { - ((u8_t *)&t)[1] = *pb++; - len--; - } - - /* Add the bulk of the data */ - ps = (u16_t *)(void *)pb; - while (len > 1) { - sum += *ps++; - len -= 2; - } - - /* Consume left-over byte, if any */ - if (len > 0) { - ((u8_t *)&t)[0] = *(u8_t *)ps; - } - - /* Add end bytes */ - sum += t; - - /* Fold 32-bit sum to 16 bits - calling this twice is propably faster than if statements... */ - sum = FOLD_U32T(sum); - sum = FOLD_U32T(sum); - - /* Swap if alignment was odd */ - if (odd) { - sum = SWAP_BYTES_IN_WORD(sum); - } - - return (u16_t)sum; -} -#endif - -#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */ -/** - * 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. - * - * @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) - * - * by Curt McDowell, Broadcom Corp. December 8th, 2005 - */ - -static u16_t ICACHE_FLASH_ATTR -lwip_standard_chksum(void *dataptr, int len) -{ - 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); - - if (odd && len > 0) { - ((u8_t *)&t)[1] = *pb++; - len--; - } - - ps = (u16_t *)pb; - - if (((mem_ptr_t)ps & 3) && len > 1) { - sum += *ps++; - len -= 2; - } - - pl = (u32_t *)ps; - - while (len > 7) { - tmp = sum + *pl++; /* ping */ - if (tmp < sum) { - tmp++; /* add back carry */ - } - - sum = tmp + *pl++; /* pong */ - if (sum < tmp) { - sum++; /* add back carry */ - } - - len -= 8; - } - - /* make room in upper bits */ - sum = FOLD_U32T(sum); - - ps = (u16_t *)pl; - - /* 16-bit aligned word remaining? */ - while (len > 1) { - sum += *ps++; - len -= 2; - } - - /* dangling tail byte remaining? */ - if (len > 0) { /* include odd byte */ - ((u8_t *)&t)[0] = *(u8_t *)ps; - } - - sum += t; /* add end bytes */ - - /* Fold 32-bit sum to 16 bits - calling this twice is propably faster than if statements... */ - sum = FOLD_U32T(sum); - sum = FOLD_U32T(sum); - - if (odd) { - sum = SWAP_BYTES_IN_WORD(sum); - } - - return (u16_t)sum; -} -#endif - -/* inet_chksum_pseudo: - * - * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. - * IP addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ip address (used for checksum of pseudo header) - * @param dst destination ip address (used for checksum of pseudo header) - * @param proto ip protocol (used for checksum of pseudo header) - * @param proto_len length of the ip data part (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -inet_chksum_pseudo(struct pbuf *p, - 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; - - acc = 0; - swapped = 0; - /* iterate through all pbuf in chain */ - for(q = p; q != NULL; q = q->next) { - LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", - (void *)q, (void *)q->next)); - acc += LWIP_CHKSUM(q->payload, q->len); - /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ - /* just executing this next line is probably faster that the if statement needed - to check whether we really need to execute it, and does no harm */ - acc = FOLD_U32T(acc); - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = SWAP_BYTES_IN_WORD(acc); - } - /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ - } - - if (swapped) { - acc = SWAP_BYTES_IN_WORD(acc); - } - 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 propably faster than if statements... */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); - return (u16_t)~(acc & 0xffffUL); -} - -/* inet_chksum_pseudo: - * - * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. - * IP addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ip address (used for checksum of pseudo header) - * @param dst destination ip address (used for checksum of pseudo header) - * @param proto ip protocol (used for checksum of pseudo header) - * @param proto_len length of the ip data part (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -inet_chksum_pseudo_partial(struct pbuf *p, - ip_addr_t *src, ip_addr_t *dest, - u8_t proto, u16_t proto_len, u16_t chksum_len) -{ - u32_t acc; - u32_t addr; - struct pbuf *q; - u8_t swapped; - u16_t chklen; - - acc = 0; - swapped = 0; - /* iterate through all pbuf in chain */ - for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) { - LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", - (void *)q, (void *)q->next)); - chklen = q->len; - if (chklen > chksum_len) { - chklen = chksum_len; - } - acc += LWIP_CHKSUM(q->payload, chklen); - chksum_len -= chklen; - LWIP_ASSERT("delete me", chksum_len < 0x7fff); - /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ - /* fold the upper bit down */ - acc = FOLD_U32T(acc); - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = SWAP_BYTES_IN_WORD(acc); - } - /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ - } - - if (swapped) { - acc = SWAP_BYTES_IN_WORD(acc); - } - 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 propably faster than if statements... */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); - return (u16_t)~(acc & 0xffffUL); -} - -/* inet_chksum: - * - * Calculates the Internet checksum over a portion of memory. Used primarily for IP - * and ICMP. - * - * @param dataptr start of the buffer to calculate the checksum (no alignment needed) - * @param len length of the buffer to calculate the checksum - * @return checksum (as u16_t) to be saved directly in the protocol header - */ - -u16_t -inet_chksum(void *dataptr, u16_t len) -{ - return ~LWIP_CHKSUM(dataptr, len); -} - -/** - * Calculate a checksum over a chain of pbufs (without pseudo-header, much like - * inet_chksum only pbufs are used). - * - * @param p pbuf chain over that the checksum should be calculated - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -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 += LWIP_CHKSUM(q->payload, q->len); - acc = FOLD_U32T(acc); - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = SWAP_BYTES_IN_WORD(acc); - } - } - - if (swapped) { - acc = SWAP_BYTES_IN_WORD(acc); - } - return (u16_t)~(acc & 0xffffUL); -} - -/* These are some implementations for LWIP_CHKSUM_COPY, which copies data - * like MEMCPY but generates a checksum at the same time. Since this is a - * performance-sensitive function, you might want to create your own version - * in assembly targeted at your hardware by defining it in lwipopts.h: - * #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len) - */ - -#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */ -/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM. - * For architectures with big caches, data might still be in cache when - * generating the checksum after copying. - */ -u16_t -lwip_chksum_copy(void *dst, const void *src, u16_t len) -{ - MEMCPY(dst, src, len); - return LWIP_CHKSUM(dst, len); -} -#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */ diff --git a/tools/sdk/lwip/src/core/ipv4/ip.c b/tools/sdk/lwip/src/core/ipv4/ip.c deleted file mode 100644 index 89d3f11cf..000000000 --- a/tools/sdk/lwip/src/core/ipv4/ip.c +++ /dev/null @@ -1,910 +0,0 @@ -/** - * @file - * This is the IPv4 layer implementation for incoming and outgoing IP traffic. - * - * @see ip_frag.c - * - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" -#include "lwip/ip.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/ip_frag.h" -#include "lwip/inet_chksum.h" -#include "lwip/netif.h" -#include "lwip/icmp.h" -#include "lwip/igmp.h" -#include "lwip/raw.h" -#include "lwip/udp.h" -#include "lwip/tcp_impl.h" -#include "lwip/snmp.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" -#include "lwip/stats.h" -#include "arch/perf.h" - -#include - -/** Set this to 0 in the rare case of wanting to call an extra function to - * generate the IP checksum (in contrast to calculating it on-the-fly). */ -#ifndef LWIP_INLINE_IP_CHKSUM -#define LWIP_INLINE_IP_CHKSUM 1 -#endif -#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP -#define CHECKSUM_GEN_IP_INLINE 1 -#else -#define CHECKSUM_GEN_IP_INLINE 0 -#endif - -#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT) -#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1 - -/** Some defines for DHCP to let link-layer-addressed packets through while the - * netif is down. - * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT - * to return 1 if the port is accepted and 0 if the port is not accepted. - */ -#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) -/* accept DHCP client port and custom port */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \ - || (LWIP_IP_ACCEPT_UDP_PORT(port))) -#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ -/* accept custom port only */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port)) -#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ -/* accept DHCP client port only */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT)) -#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ - -#else /* LWIP_DHCP */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0 -#endif /* LWIP_DHCP */ - -/** - * The interface that provided the packet for the current callback - * invocation. - */ -struct netif *current_netif; - -/** - * Header of the input packet currently being processed. - */ -const struct ip_hdr *current_header; -/** Source IP address of current_header */ -ip_addr_t current_iphdr_src; -/** Destination IP address of current_header */ -ip_addr_t current_iphdr_dest; - -/** The IP header ID of the next outgoing IP packet */ -static u16_t ip_id; - -/** - * Finds the appropriate network interface for a given IP address. It - * searches the list of network interfaces linearly. A match is found - * if the masked IP address of the network interface equals the masked - * IP address given to the function. - * - * @param dest the destination IP address for which to find the route - * @return the netif on which to send to reach dest - */ -struct netif * -ip_route(ip_addr_t *dest) -{ - struct netif *netif; - - /* iterate through netifs */ - for(netif = netif_list; netif != NULL; netif = netif->next) { - /* network mask matches? */ - if (netif_is_up(netif)) { - if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { - /* return netif on which to forward IP packet */ - return netif; - } - } - } - /* iterate through netifs */ - for(netif = netif_list; netif != NULL; netif = netif->next) { - /* network mask matches? */ - if (netif_is_up(netif)) { - if (!ip_addr_isbroadcast(dest, netif) && netif == (struct netif *)eagle_lwip_getif(0)) { - return netif; - } - } - } - if ((netif_default == NULL) || (!netif_is_up(netif_default))) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); - IP_STATS_INC(ip.rterr); - snmp_inc_ipoutnoroutes(); - return NULL; - } - /* no matching netif found, use default netif */ - return netif_default; -} - -/** - * Finds the appropriate network interface for a source IP address. It - * searches the list of network interfaces linearly. A match is found - * if the masked IP address of the network interface equals the masked - * IP address given to the function. - * - * @param source the sourcination IP address for which to find the route - * @return the netif on which to send to reach source - */ - -struct netif *ICACHE_FLASH_ATTR -ip_router(ip_addr_t *dest, ip_addr_t *source){ - struct netif *netif; - /* iterate through netifs */ - for(netif = netif_list; netif != NULL; netif = netif->next) { - /* network mask matches? */ - - if (netif_is_up(netif)) { - if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { - /* return netif on which to forward IP packet */ - return netif; - } - } - - if (netif_is_up(netif)) { - if (ip_addr_netcmp(source, &(netif->ip_addr), &(netif->netmask))) { - /* return netif on which to forward IP packet */ - return netif; - } - } - } - - if ((netif_default == NULL) || (!netif_is_up(netif_default))) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); - IP_STATS_INC(ip.rterr); - snmp_inc_ipoutnoroutes(); - return NULL; - } - /* no matching netif found, use default netif */ - os_printf("ip_router %d %p\n", __LINE__, netif_default); - return netif_default; -} - -#if IP_FORWARD -/** - * Forwards an IP packet. It finds an appropriate route for the - * packet, decrements the TTL value of the packet, adjusts the - * checksum and outputs the packet on the appropriate interface. - * - * @param p the packet to forward (p->payload points to IP header) - * @param iphdr the IP header of the input packet - * @param inp the netif on which this packet was received - */ -static void ICACHE_FLASH_ATTR -ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) -{ - struct netif *netif; - - PERF_START; - - /* RFC3927 2.7: do not forward link-local addresses */ - if (ip_addr_islinklocal(¤t_iphdr_dest)) { - LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), - ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); - goto return_noroute; - } - - /* Find network interface where to forward this IP packet to. */ - netif = ip_route(¤t_iphdr_dest); - if (netif == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n", - ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), - ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); - goto return_noroute; - } - /* Do not forward packets onto the same network interface on which - * they arrived. */ - if (netif == inp) { - LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n")); - goto return_noroute; - } - - /* decrement TTL */ - IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); - /* send ICMP if TTL == 0 */ - if (IPH_TTL(iphdr) == 0) { - snmp_inc_ipinhdrerrors(); -#if LWIP_ICMP - /* Don't send ICMP messages in response to ICMP messages */ - if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) { - icmp_time_exceeded(p, ICMP_TE_TTL); - } -#endif /* LWIP_ICMP */ - return; - } - - /* Incrementally update the IP checksum. */ - if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffff - 0x100)) { - IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1); - } else { - IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100)); - } - - LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), - ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); - - IP_STATS_INC(ip.fw); - IP_STATS_INC(ip.xmit); - snmp_inc_ipforwdatagrams(); - - PERF_STOP("ip_forward"); - /* transmit pbuf on chosen interface */ - netif->output(netif, p, ¤t_iphdr_dest); - return; -return_noroute: - snmp_inc_ipoutnoroutes(); -} -#endif /* IP_FORWARD */ - -/** - * This function is called by the network interface device driver when - * an IP packet is received. The function does the basic checks of the - * IP header such as packet size being at least larger than the header - * size etc. If the packet was not destined for us, the packet is - * forwarded (using ip_forward). The IP checksum is always checked. - * - * Finally, the packet is sent to the upper layer protocol input function. - * - * @param p the received IP packet (p->payload points to IP header) - * @param inp the netif on which this packet was received - * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't - * processed, but currently always returns ERR_OK) - */ -err_t -ip_input(struct pbuf *p, struct netif *inp) -{ - struct ip_hdr *iphdr; - struct netif *netif; - u16_t iphdr_hlen; - u16_t iphdr_len; -#if IP_ACCEPT_LINK_LAYER_ADDRESSING - int check_ip_src=1; -#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ - - IP_STATS_INC(ip.recv); - snmp_inc_ipinreceives(); - - /* identify the IP header */ - iphdr = (struct ip_hdr *)p->payload; - if (IPH_V(iphdr) != 4) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr))); - ip_debug_print(p); - pbuf_free(p); - IP_STATS_INC(ip.err); - IP_STATS_INC(ip.drop); - snmp_inc_ipinhdrerrors(); - return ERR_OK; - } - - /* obtain IP header length in number of 32-bit words */ - iphdr_hlen = IPH_HL(iphdr); - /* calculate IP header length in bytes */ - iphdr_hlen *= 4; - /* obtain ip length in bytes */ - iphdr_len = ntohs(IPH_LEN(iphdr)); - - /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ - if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) { - if (iphdr_hlen > p->len) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", - iphdr_hlen, p->len)); - } - if (iphdr_len > p->tot_len) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", - iphdr_len, p->tot_len)); - } - /* free (drop) packet pbufs */ - pbuf_free(p); - IP_STATS_INC(ip.lenerr); - IP_STATS_INC(ip.drop); - snmp_inc_ipindiscards(); - return ERR_OK; - } - - /* verify checksum */ -#if CHECKSUM_CHECK_IP - if (inet_chksum(iphdr, iphdr_hlen) != 0) { - - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen))); - ip_debug_print(p); - pbuf_free(p); - IP_STATS_INC(ip.chkerr); - IP_STATS_INC(ip.drop); - snmp_inc_ipinhdrerrors(); - return ERR_OK; - } -#endif - - /* Trim pbuf. This should have been done at the netif layer, - * but we'll do it anyway just to be sure that its done. */ - pbuf_realloc(p, iphdr_len); - - /* copy IP addresses to aligned ip_addr_t */ - ip_addr_copy(current_iphdr_dest, iphdr->dest); - ip_addr_copy(current_iphdr_src, iphdr->src); - - /* match packet against an interface, i.e. is this packet for us? */ -#if LWIP_IGMP - if (ip_addr_ismulticast(¤t_iphdr_dest)) { - if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ¤t_iphdr_dest))) { - netif = inp; - } else { - netif = NULL; - } - } else -#endif /* LWIP_IGMP */ - { - /* start trying with inp. if that's not acceptable, start walking the - list of configured netifs. - 'first' is used as a boolean to mark whether we started walking the list */ - int first = 1; - netif = inp; - do { - LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", - ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr), - ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask), - ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask), - ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask))); - - /* interface is up and configured? */ - if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) { - /* unicast to this interface address? */ - if (ip_addr_cmp(¤t_iphdr_dest, &(netif->ip_addr)) || - /* or broadcast on this interface network address? */ - ip_addr_isbroadcast(¤t_iphdr_dest, netif)) { - LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", - netif->name[0], netif->name[1])); - /* break out of for loop */ - break; - } -#if LWIP_AUTOIP - /* connections to link-local addresses must persist after changing - the netif's address (RFC3927 ch. 1.9) */ - if ((netif->autoip != NULL) && - ip_addr_cmp(¤t_iphdr_dest, &(netif->autoip->llipaddr))) { - LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n", - netif->name[0], netif->name[1])); - /* break out of for loop */ - break; - } -#endif /* LWIP_AUTOIP */ - } - if (first) { - first = 0; - netif = netif_list; - } else { - netif = netif->next; - } - if (netif == inp) { - netif = netif->next; - } - } while(netif != NULL); - } - -#if IP_ACCEPT_LINK_LAYER_ADDRESSING - /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed - * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. - * According to RFC 1542 section 3.1.1, referred by RFC 2131). - * - * If you want to accept private broadcast communication while a netif is down, - * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.: - * - * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345)) - */ - if (netif == NULL) { - /* remote port is DHCP server? */ - if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { - struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen); - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n", - ntohs(udphdr->dest))); - if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n")); - netif = inp; - check_ip_src = 0; - } - } - } -#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ - - /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ -#if IP_ACCEPT_LINK_LAYER_ADDRESSING - /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */ - if (check_ip_src && !ip_addr_isany(¤t_iphdr_src)) -#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ - { if ((ip_addr_isbroadcast(¤t_iphdr_src, inp)) || - (ip_addr_ismulticast(¤t_iphdr_src))) { - /* packet source is not valid */ - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n")); - /* free (drop) packet pbufs */ - pbuf_free(p); - IP_STATS_INC(ip.drop); - snmp_inc_ipinaddrerrors(); - snmp_inc_ipindiscards(); - return ERR_OK; - } - } - - /* packet not for us? */ - if (netif == NULL) { - /* packet not for us, route or discard */ - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n")); -#if IP_FORWARD - /* non-broadcast packet? */ - if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp)) { - /* try to forward IP packet on (other) interfaces */ - ip_forward(p, iphdr, inp); - } else -#endif /* IP_FORWARD */ - { - snmp_inc_ipinaddrerrors(); - snmp_inc_ipindiscards(); - } - pbuf_free(p); - return ERR_OK; - } - /* packet consists of multiple fragments? */ - if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) { -#if IP_REASSEMBLY /* packet fragment reassembly code present? */ - LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n", - ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); - /* reassemble the packet*/ - p = ip_reass(p); - /* packet not fully reassembled yet? */ - if (p == NULL) { - return ERR_OK; - } - iphdr = (struct ip_hdr *)p->payload; -#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ - pbuf_free(p); - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", - ntohs(IPH_OFFSET(iphdr)))); - IP_STATS_INC(ip.opterr); - IP_STATS_INC(ip.drop); - /* unsupported protocol feature */ - snmp_inc_ipinunknownprotos(); - return ERR_OK; -#endif /* IP_REASSEMBLY */ - } - -#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */ - -#if LWIP_IGMP - /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */ - if((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) { -#else - if (iphdr_hlen > IP_HLEN) { -#endif /* LWIP_IGMP */ - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n")); - pbuf_free(p); - IP_STATS_INC(ip.opterr); - IP_STATS_INC(ip.drop); - /* unsupported protocol feature */ - snmp_inc_ipinunknownprotos(); - return ERR_OK; - } -#endif /* IP_OPTIONS_ALLOWED == 0 */ - - /* send to upper layers */ - LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n")); - ip_debug_print(p); - LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); - - current_netif = inp; - current_header = iphdr; - -#if LWIP_RAW - /* raw input did not eat the packet? */ - if (raw_input(p, inp) == 0) -#endif /* LWIP_RAW */ - { - - switch (IPH_PROTO(iphdr)) { -#if LWIP_UDP - case IP_PROTO_UDP: -#if LWIP_UDPLITE - case IP_PROTO_UDPLITE: -#endif /* LWIP_UDPLITE */ - snmp_inc_ipindelivers(); - udp_input(p, inp); - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case IP_PROTO_TCP: - snmp_inc_ipindelivers(); - tcp_input(p, inp); - break; -#endif /* LWIP_TCP */ -#if LWIP_ICMP - case IP_PROTO_ICMP: - snmp_inc_ipindelivers(); - icmp_input(p, inp); - break; -#endif /* LWIP_ICMP */ -#if LWIP_IGMP - case IP_PROTO_IGMP: - igmp_input(p, inp, ¤t_iphdr_dest); - break; -#endif /* LWIP_IGMP */ - default: -#if LWIP_ICMP - /* send ICMP destination protocol unreachable unless is was a broadcast */ - if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp) && - !ip_addr_ismulticast(¤t_iphdr_dest)) { - p->payload = iphdr; - icmp_dest_unreach(p, ICMP_DUR_PROTO); - } -#endif /* LWIP_ICMP */ - pbuf_free(p); - - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr))); - - IP_STATS_INC(ip.proterr); - IP_STATS_INC(ip.drop); - snmp_inc_ipinunknownprotos(); - } - } - - current_netif = NULL; - current_header = NULL; - ip_addr_set_any(¤t_iphdr_src); - ip_addr_set_any(¤t_iphdr_dest); - - return ERR_OK; -} - -/** - * Sends an IP packet on a network interface. This function constructs - * the IP header and calculates the IP header checksum. If the source - * IP address is NULL, the IP address of the outgoing network - * interface is filled in as source address. - * If the destination IP address is IP_HDRINCL, p is assumed to already - * include an IP header and p->payload points to it instead of the data. - * - * @param p the packet to send (p->payload points to the data, e.g. next - protocol header; if dest == IP_HDRINCL, p already includes an IP - header and p->payload points to that IP header) - * @param src the source IP address to send from (if src == IP_ADDR_ANY, the - * IP address of the netif used to send is used as source address) - * @param dest the destination IP address to send the packet to - * @param ttl the TTL value to be set in the IP header - * @param tos the TOS value to be set in the IP header - * @param proto the PROTOCOL to be set in the IP header - * @param netif the netif on which to send this packet - * @return ERR_OK if the packet was sent OK - * ERR_BUF if p doesn't have enough space for IP/LINK headers - * returns errors returned by netif->output - * - * @note ip_id: RFC791 "some host may be able to simply use - * unique identifiers independent of destination" - */ -err_t -ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, - u8_t proto, struct netif *netif) -{ -#if IP_OPTIONS_SEND - return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0); -} - -/** - * Same as ip_output_if() but with the possibility to include IP options: - * - * @ param ip_options pointer to the IP options, copied into the IP header - * @ param optlen length of ip_options - */ -err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, - u16_t optlen) -{ -#endif /* IP_OPTIONS_SEND */ - struct ip_hdr *iphdr; - ip_addr_t dest_addr; -#if CHECKSUM_GEN_IP_INLINE - u32_t chk_sum = 0; -#endif /* CHECKSUM_GEN_IP_INLINE */ - - /* pbufs passed to IP must have a ref-count of 1 as their payload pointer - gets altered as the packet is passed down the stack */ - LWIP_ASSERT("p->ref == 1", p->ref == 1); - - snmp_inc_ipoutrequests(); - - /* Should the IP header be generated or is it already included in p? */ - if (dest != IP_HDRINCL) { - u16_t ip_hlen = IP_HLEN; -#if IP_OPTIONS_SEND - u16_t optlen_aligned = 0; - if (optlen != 0) { -#if CHECKSUM_GEN_IP_INLINE - int i; -#endif /* CHECKSUM_GEN_IP_INLINE */ - /* round up to a multiple of 4 */ - optlen_aligned = ((optlen + 3) & ~3); - ip_hlen += optlen_aligned; - /* First write in the IP options */ - if (pbuf_header(p, optlen_aligned)) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n")); - IP_STATS_INC(ip.err); - snmp_inc_ipoutdiscards(); - return ERR_BUF; - } - MEMCPY(p->payload, ip_options, optlen); - if (optlen < optlen_aligned) { - /* zero the remaining bytes */ - os_memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen); - } -#if CHECKSUM_GEN_IP_INLINE - for (i = 0; i < optlen_aligned/2; i++) { - chk_sum += ((u16_t*)p->payload)[i]; - } -#endif /* CHECKSUM_GEN_IP_INLINE */ - } -#endif /* IP_OPTIONS_SEND */ - /* generate IP header */ - if (pbuf_header(p, IP_HLEN)) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n")); - - IP_STATS_INC(ip.err); - snmp_inc_ipoutdiscards(); - return ERR_BUF; - } - - iphdr = (struct ip_hdr *)p->payload; - LWIP_ASSERT("check that first pbuf can hold struct ip_hdr", - (p->len >= sizeof(struct ip_hdr))); - - IPH_TTL_SET(iphdr, ttl); - IPH_PROTO_SET(iphdr, proto); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += LWIP_MAKE_U16(proto, ttl); -#endif /* CHECKSUM_GEN_IP_INLINE */ - - /* dest cannot be NULL here */ - ip_addr_copy(iphdr->dest, *dest); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF; - chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16; -#endif /* CHECKSUM_GEN_IP_INLINE */ - - IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += iphdr->_v_hl_tos; -#endif /* CHECKSUM_GEN_IP_INLINE */ - IPH_LEN_SET(iphdr, htons(p->tot_len)); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += iphdr->_len; -#endif /* CHECKSUM_GEN_IP_INLINE */ - IPH_OFFSET_SET(iphdr, 0); - IPH_ID_SET(iphdr, htons(ip_id)); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += iphdr->_id; -#endif /* CHECKSUM_GEN_IP_INLINE */ - ++ip_id; - - if (ip_addr_isany(src)) { - ip_addr_copy(iphdr->src, netif->ip_addr); - } else { - /* src cannot be NULL here */ - ip_addr_copy(iphdr->src, *src); - } - -#if CHECKSUM_GEN_IP_INLINE - chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF; - chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16; - chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF); - chk_sum = (chk_sum >> 16) + chk_sum; - chk_sum = ~chk_sum; - iphdr->_chksum = chk_sum; /* network order */ -#else /* CHECKSUM_GEN_IP_INLINE */ - IPH_CHKSUM_SET(iphdr, 0); -#if CHECKSUM_GEN_IP - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); -#endif -#endif /* CHECKSUM_GEN_IP_INLINE */ - } else { - /* IP header already included in p */ - iphdr = (struct ip_hdr *)p->payload; - ip_addr_copy(dest_addr, iphdr->dest); - dest = &dest_addr; - } - - IP_STATS_INC(ip.xmit); - - LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); - ip_debug_print(p); - -#if ENABLE_LOOPBACK - if (ip_addr_cmp(dest, &netif->ip_addr)) { - /* Packet to self, enqueue it for loopback */ - LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); - return netif_loop_output(netif, p, dest); - } -#if LWIP_IGMP - if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { - netif_loop_output(netif, p, dest); - } -#endif /* LWIP_IGMP */ -#endif /* ENABLE_LOOPBACK */ -#if IP_FRAG - /* don't fragment if interface has mtu set to 0 [loopif] */ - if (netif->mtu && (p->tot_len > netif->mtu)) { - return ip_frag(p, netif, dest); - } -#endif /* IP_FRAG */ - - LWIP_DEBUGF(IP_DEBUG, ("netif->output()\n")); - return netif->output(netif, p, dest); -} - -/** - * Simple interface to ip_output_if. It finds the outgoing network - * interface and calls upon ip_output_if to do the actual work. - * - * @param p the packet to send (p->payload points to the data, e.g. next - protocol header; if dest == IP_HDRINCL, p already includes an IP - header and p->payload points to that IP header) - * @param src the source IP address to send from (if src == IP_ADDR_ANY, the - * IP address of the netif used to send is used as source address) - * @param dest the destination IP address to send the packet to - * @param ttl the TTL value to be set in the IP header - * @param tos the TOS value to be set in the IP header - * @param proto the PROTOCOL to be set in the IP header - * - * @return ERR_RTE if no route is found - * see ip_output_if() for more return values - */ -err_t -ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto) -{ - struct netif *netif; - - /* pbufs passed to IP must have a ref-count of 1 as their payload pointer - gets altered as the packet is passed down the stack */ - LWIP_ASSERT("p->ref == 1", p->ref == 1); - - if ((netif = ip_route(dest)) == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); - IP_STATS_INC(ip.rterr); - return ERR_RTE; - } - - return ip_output_if(p, src, dest, ttl, tos, proto, netif); -} - -#if LWIP_NETIF_HWADDRHINT -/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint - * before calling ip_output_if. - * - * @param p the packet to send (p->payload points to the data, e.g. next - protocol header; if dest == IP_HDRINCL, p already includes an IP - header and p->payload points to that IP header) - * @param src the source IP address to send from (if src == IP_ADDR_ANY, the - * IP address of the netif used to send is used as source address) - * @param dest the destination IP address to send the packet to - * @param ttl the TTL value to be set in the IP header - * @param tos the TOS value to be set in the IP header - * @param proto the PROTOCOL to be set in the IP header - * @param addr_hint address hint pointer set to netif->addr_hint before - * calling ip_output_if() - * - * @return ERR_RTE if no route is found - * see ip_output_if() for more return values - */ -err_t -ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) -{ - struct netif *netif; - err_t err; - - /* pbufs passed to IP must have a ref-count of 1 as their payload pointer - gets altered as the packet is passed down the stack */ - LWIP_ASSERT("p->ref == 1", p->ref == 1); - - if ((netif = ip_route(dest)) == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); - IP_STATS_INC(ip.rterr); - return ERR_RTE; - } - - netif->addr_hint = addr_hint; - err = ip_output_if(p, src, dest, ttl, tos, proto, netif); - netif->addr_hint = NULL; - - return err; -} -#endif /* LWIP_NETIF_HWADDRHINT*/ - -#if IP_DEBUG -/* Print an IP header by using LWIP_DEBUGF - * @param p an IP packet, p->payload pointing to the IP header - */ -void -ip_debug_print(struct pbuf *p) -{ - struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; - u8_t *payload; - - payload = (u8_t *)iphdr + IP_HLEN; - - LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n", - IPH_V(iphdr), - IPH_HL(iphdr), - IPH_TOS(iphdr), - ntohs(IPH_LEN(iphdr)))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n", - ntohs(IPH_ID(iphdr)), - ntohs(IPH_OFFSET(iphdr)) >> 15 & 1, - ntohs(IPH_OFFSET(iphdr)) >> 14 & 1, - ntohs(IPH_OFFSET(iphdr)) >> 13 & 1, - ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n", - IPH_TTL(iphdr), - IPH_PROTO(iphdr), - ntohs(IPH_CHKSUM(iphdr)))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", - ip4_addr1_16(&iphdr->src), - ip4_addr2_16(&iphdr->src), - ip4_addr3_16(&iphdr->src), - ip4_addr4_16(&iphdr->src))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n", - ip4_addr1_16(&iphdr->dest), - ip4_addr2_16(&iphdr->dest), - ip4_addr3_16(&iphdr->dest), - ip4_addr4_16(&iphdr->dest))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); -} -#endif /* IP_DEBUG */ diff --git a/tools/sdk/lwip/src/core/ipv4/ip_addr.c b/tools/sdk/lwip/src/core/ipv4/ip_addr.c deleted file mode 100644 index e2df58d35..000000000 --- a/tools/sdk/lwip/src/core/ipv4/ip_addr.c +++ /dev/null @@ -1,329 +0,0 @@ -/** - * @file - * This is the IPv4 address tools implementation. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#include "lwip/opt.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" - -/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */ -const ip_addr_t ip_addr_any ICACHE_RODATA_ATTR = { IPADDR_ANY }; -const ip_addr_t ip_addr_broadcast ICACHE_RODATA_ATTR = { IPADDR_BROADCAST }; - -/** - * Determine if an address is a broadcast address on a network interface - * - * @param addr address to be checked - * @param netif the network interface against which the address is checked - * @return returns non-zero if the address is a broadcast address - */ -u8_t -ip4_addr_isbroadcast(u32_t addr, const struct netif *netif) -{ - ip_addr_t ipaddr; - ip4_addr_set_u32(&ipaddr, addr); - - /* all ones (broadcast) or all zeroes (old skool broadcast) */ - if ((~addr == IPADDR_ANY) || - (addr == IPADDR_ANY)) { - return 1; - /* no broadcast support on this network interface? */ - } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) { - /* the given address cannot be a broadcast address - * nor can we check against any broadcast addresses */ - return 0; - /* address matches network interface address exactly? => no broadcast */ - } else if (addr == ip4_addr_get_u32(&netif->ip_addr)) { - return 0; - /* on the same (sub) network... */ - } else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask)) - /* ...and host identifier bits are all ones? =>... */ - && ((addr & ~ip4_addr_get_u32(&netif->netmask)) == - (IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) { - /* => network broadcast address */ - return 1; - } else { - return 0; - } -} - -/** Checks if a netmask is valid (starting with ones, then only zeros) - * - * @param netmask the IPv4 netmask to check (in network byte order!) - * @return 1 if the netmask is valid, 0 if it is not - */ -u8_t -ip4_addr_netmask_valid(u32_t netmask) -{ - u32_t mask; - u32_t nm_hostorder = lwip_htonl(netmask); - - /* first, check for the first zero */ - for (mask = 1U << 31 ; mask != 0; mask >>= 1) { - if ((nm_hostorder & mask) == 0) { - break; - } - } - /* then check that there is no one */ - for (; mask != 0; mask >>= 1) { - if ((nm_hostorder & mask) != 0) { - /* there is a one after the first zero -> invalid */ - return 0; - } - } - /* no one after the first zero -> valid */ - return 1; -} - -/* Here for now until needed in other places in lwIP */ -#ifndef isprint -#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) -#define isprint(c) in_range(c, 0x20, 0x7f) -//#define isdigit(c) in_range(c, '0', '9') -//#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) -#define islower(c) in_range(c, 'a', 'z') -#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') -#endif - -/** - * Ascii internet address interpretation routine. - * The value returned is in network order. - * - * @param cp IP address in ascii represenation (e.g. "127.0.0.1") - * @return ip address in network order - */ -u32_t -ipaddr_addr(const char *cp) -{ - ip_addr_t val; - - if (ipaddr_aton(cp, &val)) { - return ip4_addr_get_u32(&val); - } - return (IPADDR_NONE); -} - -/** - * Check whether "cp" is a valid ascii representation - * of an Internet address and convert to a binary address. - * Returns 1 if the address is valid, 0 if not. - * This replaces inet_addr, the return value from which - * cannot distinguish between failure and a local broadcast address. - * - * @param cp IP address in ascii represenation (e.g. "127.0.0.1") - * @param addr pointer to which to save the ip address in network order - * @return 1 if cp could be converted to addr, 0 on failure - */ -int -ipaddr_aton(const char *cp, ip_addr_t *addr) -{ - u32_t val; - u8_t base; - char c; - char ch; - unsigned long cutoff; - int cutlim; - u32_t parts[4]; - u32_t *pp = parts; - - c = *cp; - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, 1-9=decimal. - */ - if (!isdigit(c)) - return (0); - val = 0; - base = 10; - if (c == '0') { - c = *++cp; - if (c == 'x' || c == 'X') { - base = 16; - c = *++cp; - } else - base = 8; - } - - cutoff =(unsigned long)0xffffffff / (unsigned long)base; - cutlim =(unsigned long)0xffffffff % (unsigned long)base; - - for (;;) { - if (isdigit(c)) { - ch = (int)(c - '0'); - - if (val > cutoff || (val == cutoff && ch > cutlim)) - return (0); - - val = (val * base) + (int)(c - '0'); - c = *++cp; - } else if (base == 16 && isxdigit(c)) { - ch = (int)(c + 10 - (islower(c) ? 'a' : 'A')); - - if (val > cutoff || (val == cutoff && ch > cutlim)) - return (0); - - val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A')); - c = *++cp; - } else - break; - } - if (c == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16 bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3) { - return (0); - } - *pp++ = val; - c = *++cp; - } else - break; - } - /* - * Check for trailing characters. - */ - if (c != '\0' && !isspace(c)) { - return (0); - } - /* - * Concoct the address according to - * the number of parts specified. - */ - switch (pp - parts + 1) { - - case 0: - return (0); /* initial nondigit */ - - case 1: /* a -- 32 bits */ - break; - - case 2: /* a.b -- 8.24 bits */ - if ((val > 0xffffffUL) || (parts[0] > 0xff)) { - return (0); - } - val |= parts[0] << 24; - break; - - case 3: /* a.b.c -- 8.8.16 bits */ - if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff)) { - return (0); - } - val |= (parts[0] << 24) | (parts[1] << 16); - break; - - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) { - return (0); - } - val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); - break; - default: - LWIP_ASSERT("unhandled", 0); - break; - } - if (addr) { - ip4_addr_set_u32(addr, htonl(val)); - } - return (1); -} - -/** - * Convert numeric IP address into decimal dotted ASCII representation. - * returns ptr to static buffer; not reentrant! - * - * @param addr ip address in network order to convert - * @return pointer to a global static (!) buffer that holds the ASCII - * represenation of addr - */ -char * -ipaddr_ntoa(const ip_addr_t *addr) -{ - static char str[16]; - return ipaddr_ntoa_r(addr, str, 16); -} - -/** - * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. - * - * @param addr ip address in network order to convert - * @param buf target buffer where the string is stored - * @param buflen length of buf - * @return either pointer to buf which now holds the ASCII - * representation of addr or NULL if buf was too small - */ -char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen) -{ - u32_t s_addr; - char inv[3]; - char *rp; - u8_t *ap; - u8_t rem; - u8_t n; - u8_t i; - int len = 0; - - s_addr = ip4_addr_get_u32(addr); - - rp = buf; - ap = (u8_t *)&s_addr; - for(n = 0; n < 4; n++) { - i = 0; - do { - rem = *ap % (u8_t)10; - *ap /= (u8_t)10; - inv[i++] = '0' + rem; - } while(*ap); - while(i--) { - if (len++ >= buflen) { - return NULL; - } - *rp++ = inv[i]; - } - if (len++ >= buflen) { - return NULL; - } - *rp++ = '.'; - ap++; - } - *--rp = 0; - return buf; -} diff --git a/tools/sdk/lwip/src/core/ipv4/ip_frag.c b/tools/sdk/lwip/src/core/ipv4/ip_frag.c deleted file mode 100644 index b89eeb587..000000000 --- a/tools/sdk/lwip/src/core/ipv4/ip_frag.c +++ /dev/null @@ -1,863 +0,0 @@ -/** - * @file - * This is the IPv4 packet segmentation and reassembly 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: Jani Monoses - * Simon Goldschmidt - * original reassembly code by Adam Dunkels - * - */ - -#include "lwip/opt.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" - -#include - -#if IP_REASSEMBLY -/** - * The IP reassembly code currently has the following limitations: - * - IP header options are not supported - * - fragments must not overlap (e.g. due to different routes), - * currently, overlapping or duplicate fragments are thrown away - * if IP_REASS_CHECK_OVERLAP=1 (the default)! - * - * @todo: work with IP header options - */ - -/** Setting this to 0, you can turn off checking the fragments for overlapping - * regions. The code gets a little smaller. Only use this if you know that - * overlapping won't occur on your network! */ -#ifndef IP_REASS_CHECK_OVERLAP -#define IP_REASS_CHECK_OVERLAP 1 -#endif /* IP_REASS_CHECK_OVERLAP */ - -/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is - * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller. - * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA - * is set to 1, so one datagram can be reassembled at a time, only. */ -#ifndef IP_REASS_FREE_OLDEST -#define IP_REASS_FREE_OLDEST 1 -#endif /* IP_REASS_FREE_OLDEST */ - -#define IP_REASS_FLAG_LASTFRAG 0x01 - -/** This is a helper struct which holds the starting - * offset and the ending offset of this fragment to - * easily chain the fragments. - * It has the same packing requirements as the IP header, since it replaces - * the IP header in memory in incoming fragments (after copying it) to keep - * track of the various fragments. (-> If the IP header doesn't need packing, - * this struct doesn't need packing, too.) - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip_reass_helper { - PACK_STRUCT_FIELD(struct pbuf *next_pbuf); - PACK_STRUCT_FIELD(u16_t start); - PACK_STRUCT_FIELD(u16_t end); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \ - (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \ - ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \ - IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0 - -/* global variables */ -static struct ip_reassdata *reassdatagrams; -static u16_t ip_reass_pbufcount; - -/* function prototypes */ -static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)ICACHE_FLASH_ATTR; -static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)ICACHE_FLASH_ATTR; - -/** - * Reassembly timer base function - * for both NO_SYS == 0 and 1 (!). - * - * Should be called every 1000 msec (defined by IP_TMR_INTERVAL). - */ -void -ip_reass_tmr(void) -{ - struct ip_reassdata *r, *prev = NULL; - - r = reassdatagrams; - while (r != NULL) { - /* Decrement the timer. Once it reaches 0, - * clean up the incomplete fragment assembly */ - if (r->timer > 0) { - r->timer--; - LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer)); - prev = r; - r = r->next; - } else { - /* reassembly timed out */ - struct ip_reassdata *tmp; - LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n")); - tmp = r; - /* get the next pointer before freeing */ - r = r->next; - /* free the helper struct and all enqueued pbufs */ - ip_reass_free_complete_datagram(tmp, prev); - } - } -} - -/** - * Free a datagram (struct ip_reassdata) and all its pbufs. - * Updates the total count of enqueued pbufs (ip_reass_pbufcount), - * SNMP counters and sends an ICMP time exceeded packet. - * - * @param ipr datagram to free - * @param prev the previous datagram in the linked list - * @return the number of pbufs freed - */ -static int -ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) -{ - u16_t pbufs_freed = 0; - u8_t clen; - struct pbuf *p; - struct ip_reass_helper *iprh; - - LWIP_ASSERT("prev != ipr", prev != ipr); - if (prev != NULL) { - LWIP_ASSERT("prev->next == ipr", prev->next == ipr); - } - - snmp_inc_ipreasmfails(); -#if LWIP_ICMP - iprh = (struct ip_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, copy the original header into it. */ - SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN); - icmp_time_exceeded(p, ICMP_TE_FRAG); - clen = pbuf_clen(p); - LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); - pbufs_freed += clen; - pbuf_free(p); - } -#endif /* LWIP_ICMP */ - - /* 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 ip_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 ip_reassdata from the list and free it. */ - ip_reass_dequeue_datagram(ipr, prev); - LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed); - ip_reass_pbufcount -= pbufs_freed; - - return pbufs_freed; -} - -#if IP_REASS_FREE_OLDEST -/** - * Free the oldest datagram to make room for enqueueing new fragments. - * The datagram 'fraghdr' belongs to is not freed! - * - * @param fraghdr IP header of the current fragment - * @param pbufs_needed number of pbufs needed to enqueue - * (used for freeing other datagrams if not enough space) - * @return the number of pbufs freed - */ -static int -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; - int pbufs_freed = 0, pbufs_freed_current; - int other_datagrams; - - /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, - * but don't free the datagram that 'fraghdr' belongs to! */ - do { - oldest = NULL; - prev = NULL; - other_datagrams = 0; - r = reassdatagrams; - while (r != NULL) { - if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) { - /* Not the same datagram as fraghdr */ - other_datagrams++; - if (oldest == NULL) { - oldest = r; - } else if (r->timer <= oldest->timer) { - /* older than the previous oldest */ - oldest = r; - } - } - if (r->next != NULL) { - prev = r; - } - r = r->next; - } - if (oldest != NULL) { - pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev); - pbufs_freed += pbufs_freed_current; - } - } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1)); - return pbufs_freed; -} -#endif /* IP_REASS_FREE_OLDEST */ - -/** - * Enqueues a new fragment into the fragment queue - * @param fraghdr points to the new fragments IP hdr - * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space) - * @return A pointer to the queue location into which the fragment was enqueued - */ -static struct ip_reassdata* ICACHE_FLASH_ATTR -ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen) -{ - struct ip_reassdata* ipr; - /* No matching previous fragment found, allocate a new reassdata struct */ - ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); - if (ipr == NULL) { -#if IP_REASS_FREE_OLDEST - if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) { - ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); - } - if (ipr == NULL) -#endif /* IP_REASS_FREE_OLDEST */ - { - IPFRAG_STATS_INC(ip_frag.memerr); - LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n")); - return NULL; - } - } - os_memset(ipr, 0, sizeof(struct ip_reassdata)); - ipr->timer = IP_REASS_MAXAGE; - - /* enqueue the new structure to the front of the list */ - ipr->next = reassdatagrams; - reassdatagrams = ipr; - /* copy the ip header for later tests and input */ - /* @todo: no ip options supported? */ - SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN); - return ipr; -} - -/** - * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs. - * @param ipr points to the queue entry to dequeue - */ -static void ICACHE_FLASH_ATTR -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 */ - reassdatagrams = ipr->next; - } else { - /* it wasn't the first, so it must have a valid 'prev' */ - LWIP_ASSERT("sanity check linked list", prev != NULL); - prev->next = ipr->next; - } - - /* now we can free the ip_reass struct */ - memp_free(MEMP_REASSDATA, ipr); -} - -/** - * Chain a new pbuf into the pbuf list that composes the datagram. The pbuf list - * 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 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 - */ -static int ICACHE_FLASH_ATTR -ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p) -{ - struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; - struct pbuf *q; - 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 = 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. */ - /* make sure the struct ip_reass_helper fits into the IP header */ - LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN", - sizeof(struct ip_reass_helper) <= IP_HLEN); - iprh = (struct ip_reass_helper*)new_p->payload; - iprh->next_pbuf = NULL; - iprh->start = offset; - iprh->end = offset + len; - - /* 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 ip_reass_helper*)q->payload; - if (iprh->start < iprh_tmp->start) { - /* the new pbuf should be inserted before this */ - iprh->next_pbuf = q; - if (iprh_prev != NULL) { - /* not the fragment with the lowest offset */ -#if IP_REASS_CHECK_OVERLAP - if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) { - /* fragment overlaps with previous or following, throw away */ - goto freepbuf; - } -#endif /* IP_REASS_CHECK_OVERLAP */ - iprh_prev->next_pbuf = new_p; - } else { - /* fragment with the lowest offset */ - ipr->p = new_p; - } - break; - } 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) { - /* 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 wholes. */ - 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 = new_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 = new_p; - } - } - - /* 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 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 (((struct ip_reass_helper*)ipr->p->payload)->start != 0) { - valid = 0; - } else { - /* and check that there are no wholes after this datagram */ - iprh_prev = iprh; - q = iprh->next_pbuf; - while (q != NULL) { - iprh = (struct ip_reass_helper*)q->payload; - if (iprh_prev->end != iprh->start) { - valid = 0; - break; - } - iprh_prev = iprh; - q = iprh->next_pbuf; - } - /* if still valid, all fragments are received - * (because to the MF==0 already arrived */ - if (valid) { - LWIP_ASSERT("sanity check", ipr->p != NULL); - LWIP_ASSERT("sanity check", - ((struct ip_reass_helper*)ipr->p->payload) != iprh); - LWIP_ASSERT("validate_datagram:next_pbuf!=NULL", - iprh->next_pbuf == NULL); - LWIP_ASSERT("validate_datagram:datagram end!=datagram len", - iprh->end == ipr->datagram_len); - } - } - } - /* If valid is 0 here, there are some fragments missing in the middle - * (since MF == 0 has already arrived). Such datagrams simply time out if - * no more fragments are received... */ - return valid; - } - /* If we come here, not all fragments were received, yet! */ - return 0; /* not yet valid! */ -#if IP_REASS_CHECK_OVERLAP -freepbuf: - ip_reass_pbufcount -= pbuf_clen(new_p); - pbuf_free(new_p); - return 0; -#endif /* IP_REASS_CHECK_OVERLAP */ -} - -/** - * Reassembles incoming IP fragments into an IP datagram. - * - * @param p points to a pbuf chain of the fragment - * @return NULL if reassembly is incomplete, ? otherwise - */ -struct pbuf * -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; - u8_t clen; - struct ip_reassdata *ipr_prev = NULL; - - IPFRAG_STATS_INC(ip_frag.recv); - snmp_inc_ipreasmreqds(); - - fraghdr = (struct ip_hdr*)p->payload; - - if ((IPH_HL(fraghdr) * 4) != IP_HLEN) { - LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n")); - IPFRAG_STATS_INC(ip_frag.err); - goto nullreturn; - } - - 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); - if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { -#if IP_REASS_FREE_OLDEST - if (!ip_reass_remove_oldest_datagram(fraghdr, clen) || - ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)) -#endif /* IP_REASS_FREE_OLDEST */ - { - /* No datagram could be freed and still too many pbufs enqueued */ - 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? */ - /* drop this pbuf */ - goto nullreturn; - } - } - - /* 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 != 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 (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, 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) { - goto nullreturn; - } - } else { - 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 - * all options, if supported)*/ - SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN); - } - } - /* 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 - * to an existing one */ - - /* check for 'no more fragments', and update queue entry*/ - if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) { - ipr->flags |= IP_REASS_FLAG_LASTFRAG; - ipr->datagram_len = offset + len; - LWIP_DEBUGF(IP_REASS_DEBUG, - ("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)) { - /* the totally last fragment (flag more fragments = 0) was received at least - * once AND all fragments are received */ - ipr->datagram_len += IP_HLEN; - - /* save the second pbuf before copying the header over the pointer */ - r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf; - - /* 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, htons(ipr->datagram_len)); - IPH_OFFSET_SET(fraghdr, 0); - IPH_CHKSUM_SET(fraghdr, 0); - /* @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) { - iprh = (struct ip_reass_helper*)r->payload; - - /* hide the ip header for every succeding fragment */ - pbuf_header(r, -IP_HLEN); - pbuf_cat(p, r); - r = iprh->next_pbuf; - } - /* 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); - - /* Return the pbuf chain */ - return p; - } - /* the datagram is not (yet?) reassembled completely */ - LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount)); - return NULL; - -nullreturn: - LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n")); - IPFRAG_STATS_INC(ip_frag.drop); - pbuf_free(p); - return NULL; -} -#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* ICACHE_FLASH_ATTR -ip_frag_alloc_pbuf_custom_ref(void) -{ - return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); -} - -/** Free a struct pbuf_custom_ref */ -static void ICACHE_FLASH_ATTR -ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) -{ - LWIP_ASSERT("p != NULL", p != NULL); - memp_free(MEMP_FRAG_PBUF, p); -} - -/** Free-callback function to free a 'struct pbuf_custom_ref', called by - * pbuf_free. */ -static void ICACHE_FLASH_ATTR -ipfrag_free_pbuf_custom(struct pbuf *p) -{ - struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; - LWIP_ASSERT("pcr != NULL", pcr != NULL); - LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); - if (pcr->original != NULL) { - pbuf_free(pcr->original); - } - ip_frag_free_pbuf_custom_ref(pcr); -} -#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ -#endif /* IP_FRAG_USES_STATIC_BUF */ - -/** - * Fragment an IP datagram if too large for the netif. - * - * Chop the datagram in MTU sized chunks and send them in order - * 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 - * @param dest destination ip address to which to send - * - * @return ERR_OK if sent successfully, err_t otherwise - */ -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 - - /* 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; -#endif /* IP_FRAG_USES_STATIC_BUF */ - - /* Save original offset */ - tmp = ntohs(IPH_OFFSET(iphdr)); - ofo = tmp & IP_OFFMASK; - omf = tmp & IP_MF; - - left = p->tot_len - IP_HLEN; - - 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, cop, PBUF_RAM); - if (rambuf == NULL) { - return ERR_MEM; - } - LWIP_ASSERT("this needs a pbuf in one piece!", - (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); - poff += pbuf_copy_partial(p, rambuf->payload, cop, poff); - /* make room for the IP header */ - if(pbuf_header(rambuf, IP_HLEN)) { - pbuf_free(rambuf); - return ERR_MEM; - } - /* fill in the IP header */ - SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); - iphdr = rambuf->payload; -#else /* LWIP_NETIF_TX_SINGLE_PBUF */ - /* When not using a static buffer, create a chain of pbufs. - * The first will be a PBUF_RAM holding the link and IP header. - * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, - * but limited to the size of an mtu. - */ - rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM); - if (rambuf == NULL) { - 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; - - /* 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; - newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; - /* Is this pbuf already empty? */ - if (!newpbuflen) { - p = p->next; - continue; - } - pcr = ip_frag_alloc_pbuf_custom_ref(); - if (pcr == NULL) { - pbuf_free(rambuf); - return ERR_MEM; - } - /* Mirror this pbuf, although we might not need all of it. */ - newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); - if (newpbuf == NULL) { - ip_frag_free_pbuf_custom_ref(pcr); - pbuf_free(rambuf); - return ERR_MEM; - } - pbuf_ref(p); - pcr->original = p; - pcr->pc.custom_free_function = ipfrag_free_pbuf_custom; - - /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain - * so that it is removed when pbuf_dechain is later called on rambuf. - */ - pbuf_cat(rambuf, newpbuf); - left_to_copy -= newpbuflen; - if (left_to_copy) { - p = p->next; - } - } - poff = newpbuflen; -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ -#endif /* IP_FRAG_USES_STATIC_BUF */ - - /* Correct header */ - IPH_OFFSET_SET(iphdr, htons(tmp)); - IPH_LEN_SET(iphdr, htons(cop + IP_HLEN)); - IPH_CHKSUM_SET(iphdr, 0); - 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. - */ - netif->output(netif, rambuf, dest); - IPFRAG_STATS_INC(ip_frag.xmit); - - /* 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); -#endif /* IP_FRAG_USES_STATIC_BUF */ - left -= cop; - ofo += nfb; - } -#if IP_FRAG_USES_STATIC_BUF - pbuf_free(rambuf); -#endif /* IP_FRAG_USES_STATIC_BUF */ - snmp_inc_ipfragoks(); - return ERR_OK; -} -#endif /* IP_FRAG */ diff --git a/tools/sdk/lwip/src/core/mdns.c b/tools/sdk/lwip/src/core/mdns.c deleted file mode 100644 index 604d96f92..000000000 --- a/tools/sdk/lwip/src/core/mdns.c +++ /dev/null @@ -1,1137 +0,0 @@ -/** - * lwip MDNS resolver file. - * - * Created on: Jul 29, 2010 - * Author: Daniel Toma - * - - * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. - * - * 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 implements a MDNS host name and PUCK service registration. - - *----------------------------------------------------------------------------- - * Includes - *----------------------------------------------------------------------------*/ -#include "lwip/opt.h" -#if LWIP_MDNS /* don't build if not configured for use in lwipopts.h */ -#include "lwip/mdns.h" -#include "lwip/puck_def.h" -#include "lwip/udp.h" -#include "lwip/mem.h" -#include "lwip/igmp.h" -#include "osapi.h" -#include "os_type.h" -#include "user_interface.h" - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -/** DNS server IP address */ -#ifndef DNS_MULTICAST_ADDRESS -#define DNS_MULTICAST_ADDRESS ipaddr_addr("224.0.0.251") /* resolver1.opendns.com */ -#endif - -/** DNS server IP address */ -#ifndef MDNS_LOCAL -#define MDNS_LOCAL "local" /* resolver1.opendns.com */ -#endif - -/** DNS server port address */ -#ifndef DNS_MDNS_PORT -#define DNS_MDNS_PORT 5353 -#endif - -/** DNS maximum number of retries when asking for a name, before "timeout". */ -#ifndef DNS_MAX_RETRIES -#define DNS_MAX_RETRIES 4 -#endif - -/** DNS resource record max. TTL (one week as default) */ -#ifndef DNS_MAX_TTL -#define DNS_MAX_TTL 604800 -#endif - -/* DNS protocol flags */ -#define DNS_FLAG1_RESPONSE 0x84 -#define DNS_FLAG1_OPCODE_STATUS 0x10 -#define DNS_FLAG1_OPCODE_INVERSE 0x08 -#define DNS_FLAG1_OPCODE_STANDARD 0x00 -#define DNS_FLAG1_AUTHORATIVE 0x04 -#define DNS_FLAG1_TRUNC 0x02 -#define DNS_FLAG1_RD 0x01 -#define DNS_FLAG2_RA 0x80 -#define DNS_FLAG2_ERR_MASK 0x0f -#define DNS_FLAG2_ERR_NONE 0x00 -#define DNS_FLAG2_ERR_NAME 0x03 - -/* DNS protocol states */ -#define DNS_STATE_UNUSED 0 -#define DNS_STATE_NEW 1 -#define DNS_STATE_ASKING 2 -#define DNS_STATE_DONE 3 - -/* MDNS registration type */ -#define MDNS_HOSTNAME_REG 0 -#define MDNS_SERVICE_REG 1 - -/* MDNS registration type */ -#define MDNS_REG_ANSWER 1 -#define MDNS_SD_ANSWER 2 -#define MDNS_SERVICE_REG_ANSWER 3 - -/* MDNS registration time */ -#define MDNS_HOST_TIME 120 -#define MDNS_SERVICE_TIME 3600 - -/** MDNS name length with "." at the beginning and end of name*/ -#ifndef MDNS_LENGTH_ADD -#define MDNS_LENGTH_ADD 2 -#endif - -#ifdef MDNS_MAX_NAME_LENGTH -#undef MDNS_MAX_NAME_LENGTH -#endif -#define MDNS_MAX_NAME_LENGTH (256) - -PACK_STRUCT_BEGIN -/** DNS message header */ -struct mdns_hdr { - PACK_STRUCT_FIELD(u16_t id); - PACK_STRUCT_FIELD(u8_t flags1); - PACK_STRUCT_FIELD(u8_t flags2); - PACK_STRUCT_FIELD(u16_t numquestions); - PACK_STRUCT_FIELD(u16_t numanswers); - PACK_STRUCT_FIELD(u16_t numauthrr); - PACK_STRUCT_FIELD(u16_t numextrarr); -}PACK_STRUCT_STRUCT; -PACK_STRUCT_END - -#define SIZEOF_DNS_HDR 12 - -PACK_STRUCT_BEGIN -/** MDNS query message structure */ -struct mdns_query { - /* MDNS query record starts with either a domain name or a pointer - to a name already present somewhere in the packet. */PACK_STRUCT_FIELD(u16_t type); - PACK_STRUCT_FIELD(u16_t class); -}PACK_STRUCT_STRUCT; -PACK_STRUCT_END - -#define SIZEOF_DNS_QUERY 4 - -PACK_STRUCT_BEGIN -/** MDNS answer message structure */ -struct mdns_answer { - /* MDNS answer record starts with either a domain name or a pointer - to a name already present somewhere in the packet. */PACK_STRUCT_FIELD(u16_t type); - PACK_STRUCT_FIELD(u16_t class); - PACK_STRUCT_FIELD(u32_t ttl); - PACK_STRUCT_FIELD(u16_t len); -}PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#define SIZEOF_DNS_ANSWER 10 - -PACK_STRUCT_BEGIN -/** MDNS answer message structure */ -struct mdns_auth { - PACK_STRUCT_FIELD(u32_t src); -}PACK_STRUCT_STRUCT; -PACK_STRUCT_END - -#define SIZEOF_MDNS_AUTH 4 -PACK_STRUCT_BEGIN -/** MDNS service registration message structure */ -struct mdns_service { - PACK_STRUCT_FIELD(u16_t prior); - PACK_STRUCT_FIELD(u16_t weight); - PACK_STRUCT_FIELD(u16_t port); -}PACK_STRUCT_STRUCT; -PACK_STRUCT_END - -#define SIZEOF_MDNS_SERVICE 6 - -uint16 PUCK_PORT ; -os_timer_t mdns_timer; -/* forward declarations */ -static void mdns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, - struct ip_addr *addr, u16_t port); - -/*----------------------------------------------------------------------------- - * Globales - *----------------------------------------------------------------------------*/ - -/* MDNS variables */ -static char host_name[MDNS_NAME_LENGTH]; -static char service_name[MDNS_NAME_LENGTH]; -static char server_name[MDNS_NAME_LENGTH]; -//static char puck_datasheet[PUCK_DATASHEET_SIZE]; -static struct udp_pcb *mdns_pcb = NULL; -static struct mdns_info * ms_info = NULL; -static struct ip_addr multicast_addr; -static struct ip_addr host_addr; -static uint8 register_flag = 0; -static uint8 mdns_flag = 0; -//#if (DNS_USES_STATIC_BUF == 1) -static u8_t mdns_payload[DNS_MSG_SIZE]; -//#endif /* (MDNS_USES_STATIC_BUF == 1) */ -/* - * Function to set the UDP pcb used to send the mDNS packages - */ -void ICACHE_FLASH_ATTR -getPcb(struct udp_pcb *pcb) { - mdns_pcb = pcb; -} - -#if DNS_DOES_NAME_CHECK -/** - * Compare the "dotted" name "query" with the encoded name "response" - * to make sure an answer from the DNS server matches the current mdns_table - * entry (otherwise, answers might arrive late for hostname not on the list - * any more). - * - * @param query hostname (not encoded) from the mdns_table - * @param response encoded hostname in the DNS response - * @return 0: names equal; 1: names differ - */ -static u8_t ICACHE_FLASH_ATTR -mdns_compare_name(unsigned char *query, unsigned char *response) { - unsigned char n; - - do { - n = *response++; - /** @see RFC 1035 - 4.1.4. Message compression */ - if ((n & 0xc0) == 0xc0) { - /* Compressed name */ - break; - } else { - /* Not compressed name */ - while (n > 0) { - if ((*query) != (*response)) { - return 1; - } - ++response; - ++query; - --n; - }; - ++query; - } - } while (*response != 0); - - return 0; -} -#endif /* DNS_DOES_NAME_CHECK */ -/** - * Send a mDNS answer packet. - * - * @param type of answer hostname and service registration or service - * @param name to query - * @param id transaction ID in the DNS query packet - * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise - */ -static err_t ICACHE_FLASH_ATTR -mdns_answer(u16_t type, const char* name, u8_t id) { - err_t err; - struct mdns_hdr *hdr; - struct mdns_answer ans; - struct mdns_auth auth; - struct mdns_service serv; - struct pbuf *p ,*p_sta; - char *query, *nptr; - const char *pHostname; - struct netif * sta_netif = NULL; - struct netif * ap_netif = NULL; - static char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH]; - u8_t n; - u16_t length = 0; - /* if here, we have either a new query or a retry on a previous query to process */ - p = pbuf_alloc(PBUF_TRANSPORT, - SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM); - if (p != NULL) { - LWIP_ASSERT("pbuf must be in one piece", p->next == NULL); - /* fill dns header */ - hdr = (struct mdns_hdr*) p->payload; - os_memset(hdr, 0, SIZEOF_DNS_HDR); - hdr->id = htons(id); - hdr->flags1 = DNS_FLAG1_RESPONSE; - - if (type == MDNS_SD_ANSWER) { - pHostname = DNS_SD_SERVICE; - hdr->numanswers = htons(1); - } else if (type == MDNS_SERVICE_REG_ANSWER) { - pHostname = PUCK_SERVICE; - hdr->numanswers = htons(type); - } else { - pHostname = name; - hdr->numanswers = htons(type); - } - query = (char*) hdr + SIZEOF_DNS_HDR; - --pHostname; - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - *query++ = '\0'; - /* fill dns query */ - - if (type == MDNS_REG_ANSWER) { - - ans.type = htons(DNS_RRTYPE_A); - ans.class = htons(DNS_RRCLASS_IN); - ans.ttl = htonl(MDNS_SERVICE_TIME); - ans.len = htons(DNS_IP_ADDR_LEN); - length = DNS_IP_ADDR_LEN; - - MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); - - /* resize the query */ - query = query + SIZEOF_DNS_ANSWER; - - /* set the local IP address */ - auth.src = host_addr.addr; - MEMCPY( query, &auth, SIZEOF_MDNS_AUTH); - } - if (type == MDNS_SD_ANSWER) { - - ans.type = htons(DNS_RRTYPE_PTR); - ans.class = htons(DNS_RRCLASS_IN); - ans.ttl = htonl(300); - ans.len = htons(os_strlen(PUCK_SERVICE) + 1 +1 ); - length = 0; - - MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); - - /* resize the query */ - query = query + SIZEOF_DNS_ANSWER; - pHostname = PUCK_SERVICE; - --pHostname; - - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - *query++ = '\0'; - } - - if (type == MDNS_SERVICE_REG_ANSWER) { - - ans.type = htons(DNS_RRTYPE_PTR); - ans.class = htons(DNS_RRCLASS_IN); - ans.ttl = htonl(MDNS_SERVICE_TIME); - os_strcpy(tmpBuf, name); - os_strcat(tmpBuf, "."); - os_strcat(tmpBuf, PUCK_SERVICE); - - length = os_strlen(tmpBuf) + MDNS_LENGTH_ADD; - ans.len = htons(length); - length = 0; - - MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); - - /* resize the query */ - query = query + SIZEOF_DNS_ANSWER; - - pHostname = tmpBuf; - --pHostname; - - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - *query++ = '\0'; - - /* Service query*/ - pHostname = name; - --pHostname; - - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - - /* Add to the service name the service local - * pointing to the beginning of the mDNS message*/ - *query++ = DNS_OFFSET_FLAG; - *query++ = DNS_DEFAULT_OFFSET; - - /* fill the query */ - - ans.type = htons(DNS_RRTYPE_SRV); - ans.class = htons(DNS_RRCLASS_FLUSH_IN); - ans.ttl = htonl(MDNS_SERVICE_TIME); - os_strcpy(tmpBuf, host_name); - os_strcat(tmpBuf, "."); - os_strcat(tmpBuf, MDNS_LOCAL); - length = os_strlen(tmpBuf) + MDNS_LENGTH_ADD; - ans.len = htons(SIZEOF_MDNS_SERVICE + length); - length = 0; - MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); - - /* resize the query */ - query = query + SIZEOF_DNS_ANSWER; - /* fill the service properties */ - - serv.prior = htons(0); - serv.weight = htons(0); - serv.port = htons(PUCK_PORT); - MEMCPY( query, &serv, SIZEOF_MDNS_SERVICE); - /* resize the query */ - query = query + SIZEOF_MDNS_SERVICE; - - pHostname = tmpBuf; - --pHostname; - - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - *query++ = '\0'; - - /* TXT answer */ - pHostname = name; - --pHostname; - - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - - /* Add to the service name the service local - * pointing to the beginning of the mDNS message*/ - *query++ = DNS_OFFSET_FLAG; - *query++ = DNS_DEFAULT_OFFSET; - - /* fill the answer */ - ans.type = htons(DNS_RRTYPE_TXT); - ans.class = htons(DNS_RRCLASS_IN); - ans.ttl = htonl(MDNS_SERVICE_TIME); - length = sizeof(SERVICE_DESCRIPTION); - ans.len = htons(length); - length = 0; - MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); - - /* resize the query */ - query = query + SIZEOF_DNS_ANSWER; - - pHostname = SERVICE_DESCRIPTION; - --pHostname; - - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - *query++ = '\0'; - } - /* resize pbuf to the exact dns query */ - pbuf_realloc(p, (query + length) - ((char*) (p->payload))); - - /* send dns packet */ - /*add by tzx for AP + STA MDNS begin------*/ - sta_netif = (struct netif *)eagle_lwip_getif(0x00); - ap_netif = (struct netif *)eagle_lwip_getif(0x01); - if(wifi_get_opmode() == 0x03 && wifi_get_broadcast_if() == 0x03 &&\ - sta_netif != NULL && ap_netif != NULL) { - if(netif_is_up(sta_netif) && netif_is_up(ap_netif)) { - - p_sta = pbuf_alloc(PBUF_TRANSPORT, - SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM); - if (pbuf_copy (p_sta,p) != ERR_OK) { - os_printf("mdns_answer copying to new pbuf failed\n"); - return -1; - } - netif_set_default(sta_netif); - err = udp_sendto(mdns_pcb, p_sta, &multicast_addr, DNS_MDNS_PORT); - pbuf_free(p_sta); - netif_set_default(ap_netif); - } - } - /*add by tzx for AP + STA MDNS end------*/ - err = udp_sendto(mdns_pcb, p, &multicast_addr, DNS_MDNS_PORT); - /* free pbuf */ - pbuf_free(p); - } else { - err = ERR_MEM; - } - - return err; -} - -/** - * Send a mDNS service answer packet. - * - * @param name service name to query - * @param id transaction ID in the DNS query packet - * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise - */ -static err_t ICACHE_FLASH_ATTR -mdns_send_service(struct mdns_info *info, u8_t id) { - err_t err; - struct mdns_hdr *hdr; - struct mdns_answer ans; - struct mdns_service serv; - struct mdns_auth auth; - struct pbuf *p ,*p_sta; - char *query, *nptr; - const char *pHostname; - char *device_info; - const char *name = info->host_name; - u8_t n; - u8_t i = 0; - u16_t length = 0; - u8_t addr1 = 12, addr2 = 12; - struct netif * sta_netif = NULL; - struct netif * ap_netif = NULL; - static char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH]; - /* if here, we have either a new query or a retry on a previous query to process */ - p = pbuf_alloc(PBUF_TRANSPORT, - SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM); - if (p != NULL) { - LWIP_ASSERT("pbuf must be in one piece", p->next == NULL); - /* fill dns header */ - hdr = (struct mdns_hdr*) p->payload; - os_memset(hdr, 0, SIZEOF_DNS_HDR); - hdr->id = htons(id); - hdr->flags1 = DNS_FLAG1_RESPONSE; - hdr->numanswers = htons(4); - query = (char*) hdr + SIZEOF_DNS_HDR; - os_strcpy(tmpBuf, PUCK_SERVICE); - - pHostname = tmpBuf; - --pHostname; - - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - ++addr1; - ++addr2; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++addr1; - ++addr2; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - *query++ = '\0'; - length = sizeof(MDNS_LOCAL); - addr1 -= length; - length = os_strlen(PUCK_SERVICE) + 1; - addr2 -= length; - - ans.type = htons(DNS_RRTYPE_PTR); - ans.class = htons(DNS_RRCLASS_IN); - ans.ttl = htonl(300); - os_strcpy(tmpBuf, name); - length = os_strlen(tmpBuf) + MDNS_LENGTH_ADD + 1; - ans.len = htons(length); - length = 0; - - MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); - /* resize the query */ - query = query + SIZEOF_DNS_ANSWER; - - pHostname = tmpBuf; - --pHostname; - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - *query++ = DNS_OFFSET_FLAG; - *query++ = DNS_DEFAULT_OFFSET; - pHostname = name; - --pHostname; - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - //*query++ = '\0'; - *query++ = DNS_OFFSET_FLAG; - *query++ = DNS_DEFAULT_OFFSET; - - /* fill the answer */ - ans.type = htons(DNS_RRTYPE_TXT); - ans.class = htons(DNS_RRCLASS_FLUSH_IN); - ans.ttl = htonl(300); -// length = os_strlen(TXT_DATA) + MDNS_LENGTH_ADD + 1; - device_info = (char *)os_zalloc(50); - ets_sprintf(device_info,"vendor = %s","Espressif"); - for(i = 0; i < 10 &&(info->txt_data[i] != NULL);i++) { - length += os_strlen(info->txt_data[i]); - length++; - } - length += os_strlen(device_info)+ 1 ; - ans.len = htons(length); - length = 0; - MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); - query = query + SIZEOF_DNS_ANSWER; - pHostname = device_info; - --pHostname; - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - i = 0; - while(info->txt_data[i] != NULL && i < 10) { - pHostname = info->txt_data[i]; - --pHostname; - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - i++; - } -// *query++ = '\0'; - os_free(device_info); - os_strcpy(tmpBuf, name); - pHostname = tmpBuf; - --pHostname; - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - - *query++ = DNS_OFFSET_FLAG; - *query++ = DNS_DEFAULT_OFFSET; - - ans.type = htons(DNS_RRTYPE_SRV); - ans.class = htons(DNS_RRCLASS_FLUSH_IN); - ans.ttl = htonl(300); - os_strcpy(tmpBuf,service_name); - os_strcat(tmpBuf, "."); - os_strcat(tmpBuf, MDNS_LOCAL); - length = os_strlen(tmpBuf) + MDNS_LENGTH_ADD; - ans.len = htons(SIZEOF_MDNS_SERVICE + length); - length = 0; - MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); - - /* resize the query */ - query = query + SIZEOF_DNS_ANSWER; - - serv.prior = htons(0); - serv.weight = htons(0); - serv.port = htons(PUCK_PORT); - MEMCPY( query, &serv, SIZEOF_MDNS_SERVICE); - /* resize the query */ - query = query + SIZEOF_MDNS_SERVICE; - - pHostname = tmpBuf; - --pHostname; - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - *query++ = '\0'; - /* set the name of the authority field. - * The same name as the Query using the offset address*/ - os_strcpy(tmpBuf,service_name); - os_strcat(tmpBuf, "."); - os_strcat(tmpBuf, MDNS_LOCAL); - pHostname = tmpBuf; - --pHostname; - do { - ++pHostname; - nptr = query; - ++query; - for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while (*pHostname != 0); - *query++ = '\0'; - /* set the name of the authority field. - * The same name as the Query using the offset address*/ - //*query++ = DNS_OFFSET_FLAG; - //*query++ = DNS_DEFAULT_OFFSET; - ans.type = htons(DNS_RRTYPE_A); - ans.class = htons(DNS_RRCLASS_FLUSH_IN); - ans.ttl = htonl(300); - ans.len = htons(DNS_IP_ADDR_LEN); - - MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); - - /* resize the query */ - query = query + SIZEOF_DNS_ANSWER; - - /* fill the payload of the mDNS message */ - /* set the local IP address */ - auth.src = host_addr.addr; //ipAddr; - MEMCPY( query, &auth, SIZEOF_MDNS_AUTH); - /* resize the query */ - query = query + SIZEOF_MDNS_AUTH; - - /* set the name of the authority field. - * The same name as the Query using the offset address*/ - - /* resize pbuf to the exact dns query */ - pbuf_realloc(p, (query) - ((char*) (p->payload))); - /* send dns packet */ - sta_netif = (struct netif *)eagle_lwip_getif(0x00); - ap_netif = (struct netif *)eagle_lwip_getif(0x01); - if(wifi_get_opmode() == 0x03 && wifi_get_broadcast_if() == 0x03 &&\ - sta_netif != NULL && ap_netif != NULL) { - if(netif_is_up(sta_netif) && netif_is_up(ap_netif)) { - - p_sta = pbuf_alloc(PBUF_TRANSPORT, - SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM); - if (pbuf_copy (p_sta,p) != ERR_OK) { - os_printf("mdns_send_service copying to new pbuf failed\n"); - return -1; - } - netif_set_default(sta_netif); - err = udp_sendto(mdns_pcb, p_sta, &multicast_addr, DNS_MDNS_PORT); - pbuf_free(p_sta); - netif_set_default(ap_netif); - } - } - err = udp_sendto(mdns_pcb, p, &multicast_addr, DNS_MDNS_PORT); - - /* free pbuf */ - pbuf_free(p); - } else { - os_printf("ERR_MEM \n"); - err = ERR_MEM; - } - - return err; -} - -/** - * Receive input function for DNS response packets arriving for the dns UDP pcb. - * - * @params see udp.h - */ -static void ICACHE_FLASH_ATTR -mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, - u16_t port) { - u8_t i; - struct mdns_hdr *hdr; - u8_t nquestions; - LWIP_UNUSED_ARG(arg); - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(addr); - LWIP_UNUSED_ARG(port); - struct mdns_info *info = (struct mdns_info *)arg; - /* is the dns message too big ? */ - if (p->tot_len > DNS_MSG_SIZE) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n")); - /* free pbuf and return */ - goto memerr1; - } - - /* is the dns message big enough ? */ - if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); - /* free pbuf and return */ - goto memerr1; - } - /* copy dns payload inside static buffer for processing */ - if (pbuf_copy_partial(p, mdns_payload, p->tot_len, 0) == p->tot_len) { - /* The ID in the DNS header should be our entry into the name table. */ - hdr = (struct mdns_hdr*) mdns_payload; - - i = htons(hdr->id); - if (i < DNS_TABLE_SIZE) { - - nquestions = htons(hdr->numquestions); - //nanswers = htons(hdr->numanswers); - /* if we have a question send an answer if necessary */ - if (nquestions > 0) { - /* MDNS_DS_DOES_NAME_CHECK */ - /* Check if the name in the "question" part match with the name of the MDNS DS service. */ - if (mdns_compare_name((unsigned char *) DNS_SD_SERVICE, - (unsigned char *) mdns_payload + SIZEOF_DNS_HDR) == 0) { - /* respond with the puck service*/ - mdns_answer(MDNS_SD_ANSWER, PUCK_SERVICE, 0); - } else if (mdns_compare_name((unsigned char *) PUCK_SERVICE, - (unsigned char *) mdns_payload + SIZEOF_DNS_HDR) == 0) { - /* respond with the puck service*/ - mdns_send_service(info, 0); - } else - goto memerr2; - } - } - } - goto memerr2; - memerr2: - os_memset(mdns_payload , 0 ,DNS_MSG_SIZE); - memerr1: - /* free pbuf */ - pbuf_free(p); - return; -} - -/** - * close the UDP pcb . - */ -void ICACHE_FLASH_ATTR -mdns_close(void) -{ - uint8 text_index = 0; - if (mdns_pcb != NULL && ms_info != NULL) { - udp_remove(mdns_pcb); - for(text_index = 0;text_index < 10;text_index++) { - if(ms_info->txt_data[text_index] != NULL) { - os_free(ms_info->txt_data[text_index]); - ms_info->txt_data[text_index] = NULL; - } - } - if (ms_info->host_name != NULL) { - os_free(ms_info->host_name); - ms_info->host_name = NULL; - } - if (ms_info->server_name != NULL) { - os_free(ms_info->server_name); - ms_info->server_name = NULL; - } - os_free(ms_info); - mdns_pcb = NULL; - ms_info = NULL; - } - -} - -void ICACHE_FLASH_ATTR -mdns_set_name(const char *name) -{ - //strcpy(host_name, name); - os_strcpy(service_name, name); -} - -void ICACHE_FLASH_ATTR -mdns_enable(void) -{ - if(mdns_flag == 0) { - udp_recv(mdns_pcb, mdns_recv, NULL); - } -} - -void ICACHE_FLASH_ATTR -mdns_disable(void) -{ - if (mdns_flag == 1) { - udp_recv(mdns_pcb, NULL, NULL); - } -} - -/** - * close the UDP pcb . - */ -char* ICACHE_FLASH_ATTR -mdns_get_hostname(void) { - //strcpy(host_name, name); - char *name = host_name; - if (host_name[0] != 0 ) { - return name; - } else { - return ("Espressif"); - } -} - -void ICACHE_FLASH_ATTR -mdns_set_hostname(char *name) { - if (name == NULL) { - os_strncpy(host_name, "Espressif", os_strlen("Espressif")+3); - return; - } - if (os_strlen(name) + 3 <= MDNS_NAME_LENGTH ){ - os_strncpy(host_name, name, os_strlen(name) ); -// os_memset(host_name + os_strlen(host_name) ,0x00,3); - } else { - os_strncpy(host_name, name, MDNS_NAME_LENGTH); - } -} - -void ICACHE_FLASH_ATTR -mdns_set_servername(const char *name) { - if (name == NULL) { - PUCK_SERVICE = "_Espressif._tcp._local"; - }else { - os_sprintf(server_name ,"_%s._tcp.local",name); - PUCK_SERVICE = server_name; - } -} - -char* ICACHE_FLASH_ATTR -mdns_get_servername(void) { - char *name = PUCK_SERVICE; - if (name == NULL) { - PUCK_SERVICE = "_Espressif._tcp._local"; - } - return name; -} - -void ICACHE_FLASH_ATTR -mdns_server_unregister(void) { - struct ip_addr ap_host_addr; - struct ip_info ipconfig; - if(register_flag == 1){ - if (igmp_leavegroup(&host_addr, &multicast_addr) != ERR_OK) { - os_printf("sta udp_leave_multigrup failed!\n"); - return; - }; - if(wifi_get_opmode() == 0x03 || wifi_get_opmode() == 0x02) { - wifi_get_ip_info(SOFTAP_IF, &ipconfig); - ap_host_addr.addr = ipconfig.ip.addr; - if (igmp_leavegroup(&ap_host_addr, &multicast_addr) != ERR_OK) { - os_printf("ap udp_join_multigrup failed!\n"); - return; - }; - } - register_flag = 0; - } -} - -void ICACHE_FLASH_ATTR -mdns_server_register(void) { - - if (register_flag == 1) { - os_printf("mdns server is already registered !\n"); - return; - } else if (igmp_joingroup(&host_addr, &multicast_addr) != ERR_OK) { - os_printf("udp_join_multigrup failed!\n"); - return; - }; - register_flag = 1; -} - -void ICACHE_FLASH_ATTR -mdns_reg(struct mdns_info *info) { - - static uint8 i = 0; - if (i <= 3) { - mdns_send_service(info,0); - i++; - } else { - os_timer_disarm(&mdns_timer); - } -} - -/** - * Initialize the resolver: set up the UDP pcb and configure the default server - * (NEW IP). - */ -void ICACHE_FLASH_ATTR -mdns_init(struct mdns_info *info) { - /* initialize default DNS server address */ - multicast_addr.addr = DNS_MULTICAST_ADDRESS; - struct ip_addr ap_host_addr; - struct ip_info ipconfig; - uint8 text_index = 0; - ms_info = (struct mdns_info *)os_zalloc(sizeof(struct mdns_info)); - if (ms_info != NULL) { - os_memcpy(ms_info,info,sizeof(struct mdns_info)); - ms_info->host_name = (char *)os_zalloc(os_strlen(info->host_name)+1); - os_memcpy(ms_info->host_name,info->host_name,os_strlen(info->host_name)); - ms_info->server_name = (char *)os_zalloc(os_strlen(info->server_name)+1); - os_memcpy(ms_info->server_name,info->server_name,os_strlen(info->server_name)); - for(text_index = 0;text_index < 10;text_index++) { - if(info->txt_data[text_index] != NULL) { - ms_info->txt_data[text_index] = (char *)os_zalloc(os_strlen(info->txt_data[text_index])+1); - os_memcpy(ms_info->txt_data[text_index],info->txt_data[text_index],os_strlen(info->txt_data[text_index])); - } else { - break; - } - - } - - } else { - os_printf("ms_info alloc failed\n"); - return; - } - if (ms_info->ipAddr == 0) { - os_printf("mdns ip error!\n "); - return; - } - host_addr.addr = ms_info->ipAddr ; - LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); - //get the datasheet from PUCK - mdns_set_hostname(ms_info->host_name); - mdns_set_servername(ms_info->server_name); - mdns_set_name(ms_info->host_name); - - // get the host name as instrumentName_serialNumber for MDNS - // set the name of the service, the same as host name - os_printf("host_name = %s\n", host_name); - os_printf("server_name = %s\n", PUCK_SERVICE); - if (ms_info->server_port == 0) - { - PUCK_PORT = 80; - } else { - PUCK_PORT = ms_info->server_port; - } - - /* initialize mDNS */ - mdns_pcb = udp_new(); - - if (mdns_pcb != NULL) { - /* join to the multicast address 224.0.0.251 */ - if(wifi_get_opmode() == 0x03 || wifi_get_opmode() == 0x01) { - if (igmp_joingroup(&host_addr, &multicast_addr) != ERR_OK) { - os_printf("sta udp_join_multigrup failed!\n"); - return; - }; - } - if(wifi_get_opmode() == 0x03 || wifi_get_opmode() == 0x02) { - wifi_get_ip_info(SOFTAP_IF, &ipconfig); - ap_host_addr.addr = ipconfig.ip.addr; - if (igmp_joingroup(&ap_host_addr, &multicast_addr) != ERR_OK) { - os_printf("ap udp_join_multigrup failed!\n"); - return; - }; - } - register_flag = 1; - /* join to any IP address at the port 5353 */ - if (udp_bind(mdns_pcb, IP_ADDR_ANY, DNS_MDNS_PORT) != ERR_OK) { - os_printf("udp_bind failed!\n"); - return; - }; - - /*loopback function for the multicast(224.0.0.251) messages received at port 5353*/ -// mdns_enable(); - udp_recv(mdns_pcb, mdns_recv, ms_info); - mdns_flag = 1; - /* - * Register the name of the instrument - */ - - os_timer_disarm(&mdns_timer); - os_timer_setfn(&mdns_timer, (os_timer_func_t *)mdns_reg,ms_info); - os_timer_arm(&mdns_timer, 1000, 1); - } -} - -#endif /* LWIP_MDNS */ diff --git a/tools/sdk/lwip/src/core/mem.c b/tools/sdk/lwip/src/core/mem.c deleted file mode 100644 index bf6263d97..000000000 --- a/tools/sdk/lwip/src/core/mem.c +++ /dev/null @@ -1,644 +0,0 @@ -/** - * @file - * Dynamic memory manager - * - * This is a lightweight replacement for the standard C library malloc(). - * - * If you want to use the standard C library malloc() instead, define - * MEM_LIBC_MALLOC to 1 in your lwipopts.h - * - * 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 - * 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 - * LWIP_MALLOC_MEMPOOL_START - * LWIP_MALLOC_MEMPOOL(20, 256) - * LWIP_MALLOC_MEMPOOL(10, 512) - * LWIP_MALLOC_MEMPOOL(5, 1512) - * LWIP_MALLOC_MEMPOOL_END - */ - -/* - * 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 - * Simon Goldschmidt - * - */ - -#include "lwip/opt.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 - -#if MEM_USE_POOLS -/* lwIP head implemented with different sized pools */ - -/** - * Allocate memory: determine the smallest pool that is big enough - * to contain an element of 'size' and get an element from that pool. - * - * @param size the size in bytes of the memory needed - * @return a pointer to the allocated memory or NULL if the pool is empty - */ -void * -mem_malloc(mem_size_t size) -{ - struct memp_malloc_helper *element; - memp_t poolnr; - mem_size_t required_size = 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_sizes[poolnr]) { - break; - } - } - if (poolnr > MEMP_POOL_LAST) { - LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); - 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; - } - - /* save the pool number this element came from */ - element->poolnr = poolnr; - /* and return a pointer to the memory directly after the struct memp_malloc_helper */ - element++; - - return element; -} - -/** - * Free memory previously allocated by mem_malloc. Loads the pool number - * and calls memp_free with that pool number to put the element back into - * its pool - * - * @param rmem the memory element to free - */ -void -mem_free(void *rmem) -{ - struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem; - - LWIP_ASSERT("rmem != NULL", (rmem != NULL)); - LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); - - /* get the original struct memp_malloc_helper */ - hmem--; - - 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)); - - /* and put it in the pool we saved earlier */ - memp_free(hmem->poolnr, hmem); -} - -#else /* MEM_USE_POOLS */ -/* lwIP replacement for your libc malloc() */ - -/** - * 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 alignes. - */ -struct mem { - /** index (-> ram[next]) of the next struct */ - mem_size_t next; - /** index (-> ram[prev]) of the previous struct */ - mem_size_t prev; - /** 1: this area is used; 0: this area is unused */ - u8_t used; - u8_t pad[3]; /* XXX: pad here instead use global ALIGN */ -} __ATTRIB_PACK; - -/** All allocated blocks will be MIN_SIZE bytes big, at least! - * MIN_SIZE can be overridden to suit your needs. Smaller values save space, - * larger values could prevent too small blocks to fragment the RAM too much. */ -#ifndef MIN_SIZE -#define MIN_SIZE 12 -#endif /* MIN_SIZE */ -/* some alignment macros: we define them here for better source code layout */ -#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE) -#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) -#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) - -/** If you want to relocate the heap to external memory, simply define - * LWIP_RAM_HEAP_POINTER as a void-pointer to that location. - * If so, make sure the memory at that location is big enough (see below on - * how that space is calculated). */ -#ifndef LWIP_RAM_HEAP_POINTER -/** the heap. we need one struct mem at the end and some room for alignment */ -/* enlarge heap as tx pbuf payload is allocate from heap as well */ -u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT] SHMEM_ATTR; -#define LWIP_RAM_HEAP_POINTER ram_heap -#endif /* LWIP_RAM_HEAP_POINTER */ - -/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ -static u8_t *ram; -/** the last entry, always unused! */ -static struct mem *ram_end; -/** pointer to the lowest free block, this is used for faster search */ -static struct mem *lfree; - -/** concurrent access protection */ -//static sys_mutex_t mem_mutex; - -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - -static volatile u8_t mem_free_count; - -/* Allow mem_free from other (e.g. interrupt) context */ -#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free) -#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free) -#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free) -#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) -#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc) -#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc) - -#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - -/* Protect the heap only by using a semaphore */ -#define LWIP_MEM_FREE_DECL_PROTECT() -#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex) -#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex) -/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */ -#define LWIP_MEM_ALLOC_DECL_PROTECT() -#define LWIP_MEM_ALLOC_PROTECT() -#define LWIP_MEM_ALLOC_UNPROTECT() - -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - - -/** - * "Plug holes" by combining adjacent empty struct mems. - * After this function is through, there should not exist - * one empty struct mem pointing to another empty struct mem. - * - * @param mem this points to a struct mem which just has been freed - * @internal this function is only called by mem_free() and mem_trim() - * - * This assumes access to the heap is protected by the calling function - * already. - */ -static void ICACHE_FLASH_ATTR -plug_holes(struct mem *mem) -{ - struct mem *nmem; - struct mem *pmem; - - LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); - LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); - LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); - - /* plug hole forward */ - LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); - - nmem = (struct mem *)(void *)&ram[mem->next]; - if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { - /* if mem->next is unused and not end of ram, combine mem and mem->next */ - if (lfree == nmem) { - lfree = mem; - } - mem->next = nmem->next; - ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram); - } - - /* plug hole backward */ - pmem = (struct mem *)(void *)&ram[mem->prev]; - if (pmem != mem && pmem->used == 0) { - /* if mem->prev is unused, combine mem and mem->prev */ - if (lfree == mem) { - lfree = pmem; - } - pmem->next = mem->next; - ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram); - } -} - -/** - * Zero the heap and initialize start, end and lowest-free - */ -void -mem_init(void) -{ - struct mem *mem; - - LWIP_ASSERT("Sanity check alignment", - (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); - - /* align the heap */ - ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER); - /* initialize the start of the heap */ - mem = (struct mem *)(void *)ram; - mem->next = MEM_SIZE_ALIGNED; - mem->prev = 0; - mem->used = 0; - /* initialize the end of the heap */ - ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED]; - ram_end->used = 1; - ram_end->next = MEM_SIZE_ALIGNED; - ram_end->prev = MEM_SIZE_ALIGNED; - - /* initialize the lowest-free pointer to the start of the heap */ - lfree = (struct mem *)(void *)ram; - - MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); - - if(sys_mutex_new(&mem_mutex) != ERR_OK) { - LWIP_ASSERT("failed to create mem_mutex", 0); - } -} - -/** - * Put a struct mem back on the heap - * - * @param rmem is the data portion of a struct mem as returned by a previous - * call to mem_malloc() - */ -void -mem_free(void *rmem) -{ - struct mem *mem; - LWIP_MEM_FREE_DECL_PROTECT(); - - if (rmem == NULL) { - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n")); - return; - } - LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0); - - LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && - (u8_t *)rmem < (u8_t *)ram_end); - - if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { - SYS_ARCH_DECL_PROTECT(lev); - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n")); - /* protect mem stats from concurrent access */ - SYS_ARCH_PROTECT(lev); - MEM_STATS_INC(illegal); - SYS_ARCH_UNPROTECT(lev); - return; - } - /* protect the heap from concurrent access */ - LWIP_MEM_FREE_PROTECT(); - /* Get the corresponding struct mem ... */ - mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); - /* ... which has to be in a used state ... */ - LWIP_ASSERT("mem_free: mem->used", mem->used); - /* ... and is now unused. */ - mem->used = 0; - - if (mem < lfree) { - /* the newly freed struct is now the lowest */ - lfree = mem; - } - - MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram))); - - /* finally, see if prev or next are free also */ - plug_holes(mem); -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - mem_free_count = 1; -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - LWIP_MEM_FREE_UNPROTECT(); -} - -/** - * Shrink memory returned by mem_malloc(). - * - * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked - * @param newsize required size after shrinking (needs to be smaller than or - * equal to the previous size) - * @return for compatibility reasons: is always == rmem, at the moment - * or NULL if newsize is > old size, in which case rmem is NOT touched - * or freed! - */ -void * -mem_trim(void *rmem, mem_size_t newsize) -{ - mem_size_t size; - mem_size_t ptr, ptr2; - struct mem *mem, *mem2; - /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ - LWIP_MEM_FREE_DECL_PROTECT(); - - /* Expand the size of the allocated memory region so that we can - adjust for alignment. */ - newsize = LWIP_MEM_ALIGN_SIZE(newsize); - - if(newsize < MIN_SIZE_ALIGNED) { - /* every data block must be at least MIN_SIZE_ALIGNED long */ - newsize = MIN_SIZE_ALIGNED; - } - - if (newsize > MEM_SIZE_ALIGNED) { - return NULL; - } - - LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram && - (u8_t *)rmem < (u8_t *)ram_end); - - if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { - SYS_ARCH_DECL_PROTECT(lev); - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n")); - /* protect mem stats from concurrent access */ - SYS_ARCH_PROTECT(lev); - MEM_STATS_INC(illegal); - SYS_ARCH_UNPROTECT(lev); - return rmem; - } - /* Get the corresponding struct mem ... */ - mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); - /* ... and its offset pointer */ - ptr = (mem_size_t)((u8_t *)mem - ram); - - size = mem->next - ptr - SIZEOF_STRUCT_MEM; - LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size); - if (newsize > size) { - /* not supported */ - return NULL; - } - if (newsize == size) { - /* No change in size, simply return */ - return rmem; - } - - /* protect the heap from concurrent access */ - LWIP_MEM_FREE_PROTECT(); - - mem2 = (struct mem *)(void *)&ram[mem->next]; - if(mem2->used == 0) { - /* The next struct is unused, we can simply move it at little */ - mem_size_t next; - /* remember the old next pointer */ - next = mem2->next; - /* create new struct mem which is moved directly after the shrinked mem */ - ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; - if (lfree == mem2) { - lfree = (struct mem *)(void *)&ram[ptr2]; - } - mem2 = (struct mem *)(void *)&ram[ptr2]; - mem2->used = 0; - /* restore the next pointer */ - mem2->next = next; - /* link it back to mem */ - mem2->prev = ptr; - /* link mem to it */ - mem->next = ptr2; - /* last thing to restore linked list: as we have moved mem2, - * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not - * the end of the heap */ - if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; - } - MEM_STATS_DEC_USED(used, (size - newsize)); - /* no need to plug holes, we've already done that */ - } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { - /* Next struct is used but there's room for another struct mem with - * at least MIN_SIZE_ALIGNED of data. - * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem - * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). - * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty - * region that couldn't hold data, but when mem->next gets freed, - * the 2 regions would be combined, resulting in more free memory */ - ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; - mem2 = (struct mem *)(void *)&ram[ptr2]; - if (mem2 < lfree) { - lfree = mem2; - } - mem2->used = 0; - mem2->next = mem->next; - mem2->prev = ptr; - mem->next = ptr2; - if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; - } - MEM_STATS_DEC_USED(used, (size - newsize)); - /* the original mem->next is used, so no need to plug holes! */ - } - /* else { - next struct mem is used but size between mem and mem2 is not big enough - to create another struct mem - -> don't do anyhting. - -> the remaining space stays unused since it is too small - } */ -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - mem_free_count = 1; -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - LWIP_MEM_FREE_UNPROTECT(); - return rmem; -} - -/** - * 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. - * @return pointer to allocated memory or NULL if no free memory was found. - * - * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT). - */ -void * -mem_malloc(mem_size_t size) -{ - mem_size_t ptr, ptr2; - struct mem *mem, *mem2; -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - u8_t local_mem_free_count = 0; -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - LWIP_MEM_ALLOC_DECL_PROTECT(); - - if (size == 0) { - return NULL; - } - - /* Expand the size of the allocated memory region so that we can - adjust for alignment. */ - size = LWIP_MEM_ALIGN_SIZE(size); - - if(size < MIN_SIZE_ALIGNED) { - /* every data block must be at least MIN_SIZE_ALIGNED long */ - size = MIN_SIZE_ALIGNED; - } - - if (size > MEM_SIZE_ALIGNED) { - return NULL; - } - - /* protect the heap from concurrent access */ - sys_mutex_lock(&mem_mutex); - LWIP_MEM_ALLOC_PROTECT(); -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - /* run as long as a mem_free disturbed mem_malloc */ - do { - local_mem_free_count = 0; -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - - /* Scan through the heap searching for a free block that is big enough, - * beginning with the lowest free block. - */ - for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size; - ptr = ((struct mem *)(void *)&ram[ptr])->next) { - mem = (struct mem *)(void *)&ram[ptr]; -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - mem_free_count = 0; - LWIP_MEM_ALLOC_UNPROTECT(); - /* allow mem_free to run */ - LWIP_MEM_ALLOC_PROTECT(); - if (mem_free_count != 0) { - local_mem_free_count = mem_free_count; - } - mem_free_count = 0; -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - - if ((!mem->used) && - (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { - /* mem is not used and at least perfect fit is possible: - * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ - - if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { - /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing - * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') - * -> split large block, create empty remainder, - * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if - * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, - * struct mem would fit in but no data between mem2 and mem2->next - * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty - * region that couldn't hold data, but when mem->next gets freed, - * the 2 regions would be combined, resulting in more free memory - */ - ptr2 = ptr + SIZEOF_STRUCT_MEM + size; - /* create mem2 struct */ - mem2 = (struct mem *)(void *)&ram[ptr2]; - mem2->used = 0; - mem2->next = mem->next; - mem2->prev = ptr; - /* and insert it between mem and mem->next */ - mem->next = ptr2; - mem->used = 1; - - if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; - } - MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); - } else { - /* (a mem2 struct does no fit into the user data space of mem and mem->next will always - * be used at this point: if not we have 2 unused structs in a row, plug_holes should have - * take care of this). - * -> near fit or excact fit: do not split, no mem2 creation - * also can't move mem->next directly behind mem, since mem->next - * will always be used at this point! - */ - mem->used = 1; - MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram)); - } - - if (mem == lfree) { - /* Find next free block after mem and update lowest free pointer */ - while (lfree->used && lfree != ram_end) { - LWIP_MEM_ALLOC_UNPROTECT(); - /* prevent high interrupt latency... */ - LWIP_MEM_ALLOC_PROTECT(); - lfree = (struct mem *)(void *)&ram[lfree->next]; - } - LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); - } - LWIP_MEM_ALLOC_UNPROTECT(); - sys_mutex_unlock(&mem_mutex); - LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", - (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); - LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", - ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); - LWIP_ASSERT("mem_malloc: sanity check alignment", - (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0); - - return (u8_t *)mem + SIZEOF_STRUCT_MEM; - } - } -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - /* if we got interrupted by a mem_free, try again */ - } while(local_mem_free_count != 0); -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); - MEM_STATS_INC(err); - LWIP_MEM_ALLOC_UNPROTECT(); - sys_mutex_unlock(&mem_mutex); - return NULL; -} - -#endif /* MEM_USE_POOLS */ -/** - * Contiguously allocates enough space for count objects that are size bytes - * of memory each and returns a pointer to the allocated memory. - * - * The allocated memory is filled with bytes of value zero. - * - * @param count number of objects to allocate - * @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 *p; - - /* allocate 'count' objects of size 'size' */ - p = mem_malloc(count * size); - if (p) { - /* zero the memory */ - os_memset(p, 0, count * size); - } - return p; -} - -#endif /* !MEM_LIBC_MALLOC */ diff --git a/tools/sdk/lwip/src/core/memp.c b/tools/sdk/lwip/src/core/memp.c deleted file mode 100644 index 38bdd1bed..000000000 --- a/tools/sdk/lwip/src/core/memp.c +++ /dev/null @@ -1,490 +0,0 @@ -/** - * @file - * Dynamic pool memory manager - * - * lwIP has dedicated pools for many structures (netconn, protocol control blocks, - * packet buffers, ...). All these pools are managed here. - */ - -/* - * 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 - * - */ - -#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 - -#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ - -struct memp { - struct memp *next; -#if MEMP_OVERFLOW_CHECK - const char *file; - int line; -#endif /* MEMP_OVERFLOW_CHECK */ -}; - -#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*/ - -/* 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) - -#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 u32_t memp_sizes[MEMP_MAX] ICACHE_RODATA_ATTR = { //LWIP_MEM_ALIGN_SIZE -#define LWIP_MEMPOOL(name,num,size,desc,attr) LWIP_MEM_ALIGN_SIZE(size), -#include "lwip/memp_std.h" -}; - -u16_t memp_sizes_test[1] = {PBUF_POOL_BUFSIZE,}; - -#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,attr) (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] = { -const char *memp_desc[MEMP_MAX] = { -#define LWIP_MEMPOOL(name,num,size,desc,attr) (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,attr) u8_t memp_memory_ ## name ## _base \ - [((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))] attr; -#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,attr) 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, attr) + ( (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, modify by ives at 2014.4.23. - */ -static int ICACHE_FLASH_ATTR -memp_sanity(void) -{ - s16_t i; - struct memp *t, *h; - - for (i = 0; i < MEMP_MAX; i++) { - t = memp_tab[i]; - if(t != NULL) { - for (h = t->next; (t != NULL) && (h != NULL); t = t->next, - h = (((h->next != NULL) && (h->next->next != NULL)) ? h->next->next : NULL)) { - if (t == h) { - return 0; - } - } - } - } - return 1; -} -#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,attr) "/"desc, -#include "lwip/memp_std.h" - }; -#endif - -/** - * Check if a memp element was victim of an overflow - * (e.g. the restricted area after it has been altered) - * - * @param p the memp element to check - * @param memp_type the pool p comes from - */ -static void ICACHE_FLASH_ATTR -memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type) -{ - u16_t k; - u8_t *m; -#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type]; - for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { - if (m[k] != 0xcd) { - char errstr[128] = "detected memp overflow in pool "; - char digit[] = "0"; - if(memp_type >= 10) { - digit[0] = '0' + (memp_type/10); - strcat(errstr, digit); - } - digit[0] = '0' + (memp_type%10); - strcat(errstr, digit); -#if defined(LWIP_DEBUG) && MEMP_STATS - strcat(errstr, memp_overflow_names[memp_type]); -#endif - LWIP_ASSERT(errstr, 0); - } - } -#endif -} - -/** - * Check if a memp element was victim of an underflow - * (e.g. the restricted area before it has been altered) - * - * @param p the memp element to check - * @param memp_type the pool p comes from - */ -static void ICACHE_FLASH_ATTR -memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type) -{ - u16_t k; - u8_t *m; -#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; - for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) { - if (m[k] != 0xcd) { - char errstr[128] = "detected memp underflow in pool "; - char digit[] = "0"; - if(memp_type >= 10) { - digit[0] = '0' + (memp_type/10); - strcat(errstr, digit); - } - digit[0] = '0' + (memp_type%10); - strcat(errstr, digit); -#if defined(LWIP_DEBUG) && MEMP_STATS - strcat(errstr, memp_overflow_names[memp_type]); -#endif - LWIP_ASSERT(errstr, 0); - } - } -#endif -} - -/** - * Do an overflow check for all elements in every pool. - * - * @see memp_overflow_check_element for a description of the check - */ -static void ICACHE_FLASH_ATTR -memp_overflow_check_all(void) -{ - u16_t i, j; - struct memp *p; - - p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); - for (i = 0; i < MEMP_MAX; ++i) { - p = p; - for (j = 0; j < memp_num[i]; ++j) { - memp_overflow_check_element_overflow(p, i); - p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); - } - } - p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); - for (i = 0; i < MEMP_MAX; ++i) { - p = p; - for (j = 0; j < memp_num[i]; ++j) { - memp_overflow_check_element_underflow(p, i); - p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); - } - } -} - -/** - * Initialize the restricted areas of all memp elements in every pool. - */ -static void ICACHE_FLASH_ATTR -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; - os_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]; - os_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) -{ - struct memp *memp; - u16_t i, j; - - 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_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 = (struct memp *)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 */ -} - -/** - * Get an element from a specific pool. - * - * @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 * -#if !MEMP_OVERFLOW_CHECK -memp_malloc(memp_t type) -#else -memp_malloc_fn(memp_t type, const char* file, const int line) -#endif -{ - 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 */ - - 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 */ - 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); - } - - SYS_ARCH_UNPROTECT(old_level); - - return memp; -} - -/** - * Put an element back into its pool. - * - * @param type the pool where to put mem - * @param mem the memp element to free - */ -void -memp_free(memp_t type, void *mem) -{ - 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 */ - - MEMP_STATS_DEC(used, type); - - memp->next = memp_tab[type]; - memp_tab[type] = memp; - -#if MEMP_SANITY_CHECK - LWIP_ASSERT("memp sanity", memp_sanity()); -#endif /* MEMP_SANITY_CHECK */ - - SYS_ARCH_UNPROTECT(old_level); -} - -#endif /* MEMP_MEM_MALLOC */ -#if 0 -void memp_dump(void) -{ - printf("sizeof raw_pcb %u, memp_s1 %u, %s\n", sizeof(struct raw_pcb), memp_sizes[0], memp_desc[0]); - printf("sizeof udp_pcb %u, memp_s2 %u, %s\n", sizeof(struct udp_pcb), memp_sizes[1], memp_desc[1]); - printf("sizeof tcp_pcb %u, memp_s3 %u, %s\n", sizeof(struct tcp_pcb), memp_sizes[2], memp_desc[2]); - printf("sizeof tcp_pcb_listen %u, memp_s4 %u, %s\n", sizeof(struct tcp_pcb_listen), memp_sizes[3], memp_desc[3]); - printf("sizeof tcp_seg %u, memp_s5 %u, %s\n", sizeof(struct tcp_seg), memp_sizes[4], memp_desc[4]); - printf("sizeof sys_timeo %u, memp_s6 %u, %s\n", sizeof(struct sys_timeo), memp_sizes[5], memp_desc[5]); - printf("sizeof pbuf %u, memp_s7 %u, %s\n", sizeof(struct pbuf), memp_sizes[6], memp_desc[6]); - printf("align pbuf size %u, memp_s8 %u, %s\n", (PBUF_POOL_BUFSIZE), memp_sizes[7], memp_desc[7]); - printf("TCP_MSS %d PBUF_LINK_HLEN %d ETH_PAD_SIZE %d\n", TCP_MSS, PBUF_LINK_HLEN, ETH_PAD_SIZE); - printf("TCP_MSS + PBUF_LINK_HLEN + ETH_PAD_SIZE %d \n", TCP_MSS+PBUF_LINK_HLEN+ETH_PAD_SIZE+40); - printf("test size %u\n",memp_sizes_test[0]); - printf("sizeof memp_memory_PBUF_pool %u \n", sizeof(memp_memory_PBUF_POOL_base)); -} -#endif //0000 diff --git a/tools/sdk/lwip/src/core/netif.c b/tools/sdk/lwip/src/core/netif.c deleted file mode 100644 index cb6b6a84e..000000000 --- a/tools/sdk/lwip/src/core/netif.c +++ /dev/null @@ -1,762 +0,0 @@ -/** - * @file - * lwIP network interface abstraction - * - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" - -#include "lwip/def.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/tcp_impl.h" -#include "lwip/snmp.h" -#include "lwip/igmp.h" -#include "netif/etharp.h" -#include "lwip/stats.h" -#if ENABLE_LOOPBACK -#include "lwip/sys.h" -#if LWIP_NETIF_LOOPBACK_MULTITHREADING -#include "lwip/tcpip.h" -#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ -#endif /* ENABLE_LOOPBACK */ - -#if LWIP_AUTOIP -#include "lwip/autoip.h" -#endif /* LWIP_AUTOIP */ -#if LWIP_DHCP -#include "lwip/dhcp.h" -#endif /* LWIP_DHCP */ - -#if LWIP_NETIF_STATUS_CALLBACK -#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0) -#else -#define NETIF_STATUS_CALLBACK(n) -#endif /* LWIP_NETIF_STATUS_CALLBACK */ - -#if LWIP_NETIF_LINK_CALLBACK -#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0) -#else -#define NETIF_LINK_CALLBACK(n) -#endif /* LWIP_NETIF_LINK_CALLBACK */ - -struct netif *netif_list; -struct netif *netif_default; - -#if LWIP_HAVE_LOOPIF -static struct netif loop_netif; - -/** - * Initialize a lwip network interface structure for a loopback interface - * - * @param netif the lwip network interface structure for this loopif - * @return ERR_OK if the loopif is initialized - * ERR_MEM if private data couldn't be allocated - */ - static err_t ICACHE_FLASH_ATTR -netif_loopif_init(struct netif *netif) -{ - /* initialize the snmp variables and counters inside the struct netif - * ifSpeed: no assumption can be made! - */ - NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0); - - netif->name[0] = 'l'; - netif->name[1] = 'o'; - netif->output = netif_loop_output; - return ERR_OK; -} -#endif /* LWIP_HAVE_LOOPIF */ - -void -netif_init(void) -{ -#if LWIP_HAVE_LOOPIF - ip_addr_t loop_ipaddr, loop_netmask, loop_gw; - IP4_ADDR(&loop_gw, 127,0,0,1); - IP4_ADDR(&loop_ipaddr, 127,0,0,1); - IP4_ADDR(&loop_netmask, 255,0,0,0); - -#if NO_SYS - netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input); -#else /* NO_SYS */ - netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input); -#endif /* NO_SYS */ - netif_set_up(&loop_netif); - -#endif /* LWIP_HAVE_LOOPIF */ -} - -/** - * Add a network interface to the list of lwIP netifs. - * - * @param netif a pre-allocated netif structure - * @param ipaddr IP address for the new netif - * @param netmask network mask for the new netif - * @param gw default gateway IP address for the new netif - * @param state opaque data passed to the new netif - * @param init callback function that initializes the interface - * @param input callback function that is called to pass - * ingress packets up in the protocol layer stack. - * - * @return netif, or NULL if failed. - */ -struct netif * -netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, - ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) -{ - static u8_t netifnum = 0; - - LWIP_ASSERT("No init function given", init != NULL); - - /* reset new interface configuration state */ - ip_addr_set_zero(&netif->ip_addr); - ip_addr_set_zero(&netif->netmask); - ip_addr_set_zero(&netif->gw); - netif->flags = 0; -#if LWIP_DHCP - /* netif not under DHCP control by default */ - netif->dhcp = NULL; - netif->dhcps_pcb = NULL; -#endif /* LWIP_DHCP */ -#if LWIP_AUTOIP - /* netif not under AutoIP control by default */ - netif->autoip = NULL; -#endif /* LWIP_AUTOIP */ -#if LWIP_NETIF_STATUS_CALLBACK - netif->status_callback = NULL; -#endif /* LWIP_NETIF_STATUS_CALLBACK */ -#if LWIP_NETIF_LINK_CALLBACK - netif->link_callback = NULL; -#endif /* LWIP_NETIF_LINK_CALLBACK */ -#if LWIP_IGMP - netif->igmp_mac_filter = NULL; -#endif /* LWIP_IGMP */ -#if ENABLE_LOOPBACK - netif->loop_first = NULL; - netif->loop_last = NULL; -#endif /* ENABLE_LOOPBACK */ - - /* remember netif specific state information data */ - netif->state = state; - netif->num = netifnum++; - netif->input = input; -#if LWIP_NETIF_HWADDRHINT - netif->addr_hint = NULL; -#endif /* LWIP_NETIF_HWADDRHINT*/ -#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS - netif->loop_cnt_current = 0; -#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ - - netif_set_addr(netif, ipaddr, netmask, gw); - - /* call user specified initialization function for netif */ - if (init(netif) != ERR_OK) { - return NULL; - } - - /* add this netif to the list */ - netif->next = netif_list; - netif_list = netif; - snmp_inc_iflist(); - -#if LWIP_IGMP - /* start IGMP processing */ - if (netif->flags & NETIF_FLAG_IGMP) { - igmp_start(netif); - } -#endif /* LWIP_IGMP */ - - LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", - netif->name[0], netif->name[1])); - ip_addr_debug_print(NETIF_DEBUG, ipaddr); - LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); - ip_addr_debug_print(NETIF_DEBUG, netmask); - LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); - ip_addr_debug_print(NETIF_DEBUG, gw); - LWIP_DEBUGF(NETIF_DEBUG, ("\n")); - return netif; -} - -/** - * Change IP address configuration for a network interface (including netmask - * and default gateway). - * - * @param netif the network interface to change - * @param ipaddr the new IP address - * @param netmask the new netmask - * @param gw the new default gateway - */ -void -netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, - ip_addr_t *gw) -{ - netif_set_ipaddr(netif, ipaddr); - netif_set_netmask(netif, netmask); - netif_set_gw(netif, gw); -} - -/** - * Remove a network interface from the list of lwIP netifs. - * - * @param netif the network interface to remove - */ -void -netif_remove(struct netif *netif) -{ - if (netif == NULL) { - return; - } - -#if LWIP_IGMP - /* stop IGMP processing */ - if (netif->flags & NETIF_FLAG_IGMP) { - igmp_stop(netif); - } -#endif /* LWIP_IGMP */ - if (netif_is_up(netif)) { - /* set netif down before removing (call callback function) */ - netif_set_down(netif); - } - - snmp_delete_ipaddridx_tree(netif); - - /* is it the first netif? */ - if (netif_list == netif) { - netif_list = netif->next; - } else { - /* look for netif further down the list */ - struct netif * tmpNetif; - for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) { - if (tmpNetif->next == netif) { - tmpNetif->next = netif->next; - break; - } - } - if (tmpNetif == NULL) - return; /* we didn't find any netif today */ - } - snmp_dec_iflist(); - /* this netif is default? */ - if (netif_default == netif) { - /* reset default netif */ - netif_set_default(NULL); - } - LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); -} - -/** - * Find a network interface by searching for its name - * - * @param name the name of the netif (like netif->name) plus concatenated number - * in ascii representation (e.g. 'en0') - */ -struct netif * -netif_find(char *name) -{ - struct netif *netif; - u8_t num; - - if (name == NULL) { - return NULL; - } - - num = name[2] - '0'; - - for(netif = netif_list; netif != NULL; netif = netif->next) { - if (num == netif->num && - name[0] == netif->name[0] && - name[1] == netif->name[1]) { - LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1])); - return netif; - } - } - LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); - return NULL; -} - -/** - * Change the IP address of a network interface - * - * @param netif the network interface to change - * @param ipaddr the new IP address - * - * @note call netif_set_addr() if you also want to change netmask and - * default gateway - */ -void -netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr) -{ - /* TODO: Handling of obsolete pcbs */ - /* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */ -#if LWIP_TCP - struct tcp_pcb *pcb; - struct tcp_pcb_listen *lpcb; - - /* address is actually being changed? */ - if (ipaddr && (ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) { - /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */ - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); - pcb = tcp_active_pcbs; - while (pcb != NULL) { - /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr)) -#if LWIP_AUTOIP - /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ - && !ip_addr_islinklocal(&(pcb->local_ip)) -#endif /* LWIP_AUTOIP */ - ) { - /* this connection must be aborted */ - struct tcp_pcb *next = pcb->next; - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); - tcp_abort(pcb); - pcb = next; - } else { - pcb = pcb->next; - } - } - for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { - /* PCB bound to current local interface address? */ - if ((!(ip_addr_isany(&(lpcb->local_ip)))) && - (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) { - /* The PCB is listening to the old ipaddr and - * is set to listen to the new one instead */ - ip_addr_set(&(lpcb->local_ip), ipaddr); - } - } - } -#endif - snmp_delete_ipaddridx_tree(netif); - snmp_delete_iprteidx_tree(0,netif); - /* set new IP address to netif */ - ip_addr_set(&(netif->ip_addr), ipaddr); - snmp_insert_ipaddridx_tree(netif); - snmp_insert_iprteidx_tree(0,netif); - - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - netif->name[0], netif->name[1], - ip4_addr1_16(&netif->ip_addr), - ip4_addr2_16(&netif->ip_addr), - ip4_addr3_16(&netif->ip_addr), - ip4_addr4_16(&netif->ip_addr))); -} - -/** - * Change the default gateway for a network interface - * - * @param netif the network interface to change - * @param gw the new default gateway - * - * @note call netif_set_addr() if you also want to change ip address and netmask - */ -void -netif_set_gw(struct netif *netif, ip_addr_t *gw) -{ - ip_addr_set(&(netif->gw), gw); - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - netif->name[0], netif->name[1], - ip4_addr1_16(&netif->gw), - ip4_addr2_16(&netif->gw), - ip4_addr3_16(&netif->gw), - ip4_addr4_16(&netif->gw))); -} - -/** - * Change the netmask of a network interface - * - * @param netif the network interface to change - * @param netmask the new netmask - * - * @note call netif_set_addr() if you also want to change ip address and - * default gateway - */ -void -netif_set_netmask(struct netif *netif, ip_addr_t *netmask) -{ - snmp_delete_iprteidx_tree(0, netif); - /* set new netmask to netif */ - ip_addr_set(&(netif->netmask), netmask); - snmp_insert_iprteidx_tree(0, netif); - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - netif->name[0], netif->name[1], - ip4_addr1_16(&netif->netmask), - ip4_addr2_16(&netif->netmask), - ip4_addr3_16(&netif->netmask), - ip4_addr4_16(&netif->netmask))); -} - -/** - * Set a network interface as the default network interface - * (used to output all packets for which no specific route is found) - * - * @param netif the default network interface - */ -void -netif_set_default(struct netif *netif) -{ - if (netif == NULL) { - /* remove default route */ - snmp_delete_iprteidx_tree(1, netif); - } else { - /* install default route */ - snmp_insert_iprteidx_tree(1, netif); - } - netif_default = netif; - LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", - netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); -} - -/** - * Bring an interface up, available for processing - * traffic. - * - * @note: Enabling DHCP on a down interface will make it come - * up once configured. - * - * @see dhcp_start() - */ -void netif_set_up(struct netif *netif) -{ - if (!(netif->flags & NETIF_FLAG_UP)) { - netif->flags |= NETIF_FLAG_UP; - -#if LWIP_SNMP - snmp_get_sysuptime(&netif->ts); -#endif /* LWIP_SNMP */ - - NETIF_STATUS_CALLBACK(netif); - - if (netif->flags & NETIF_FLAG_LINK_UP) { -#if LWIP_ARP - /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ - if (netif->flags & (NETIF_FLAG_ETHARP)) { - etharp_gratuitous(netif); - } -#endif /* LWIP_ARP */ - -#if LWIP_IGMP - /* resend IGMP memberships */ - if (netif->flags & NETIF_FLAG_IGMP) { - igmp_report_groups( netif); - } -#endif /* LWIP_IGMP */ - } - } -} - -/** - * Bring an interface down, disabling any traffic processing. - * - * @note: Enabling DHCP on a down interface will make it come - * up once configured. - * - * @see dhcp_start() - */ -void netif_set_down(struct netif *netif) -{ - if (netif == NULL) { - return; - } - - if (netif->flags & NETIF_FLAG_UP) { - netif->flags &= ~NETIF_FLAG_UP; -#if LWIP_SNMP - snmp_get_sysuptime(&netif->ts); -#endif - -#if LWIP_ARP - if (netif->flags & NETIF_FLAG_ETHARP) { - etharp_cleanup_netif(netif); - } -#endif /* LWIP_ARP */ - NETIF_STATUS_CALLBACK(netif); - } -} - -#if LWIP_NETIF_STATUS_CALLBACK -/** - * Set callback to be called when interface is brought up/down - */ -void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback) -{ - if (netif) { - netif->status_callback = status_callback; - } -} -#endif /* LWIP_NETIF_STATUS_CALLBACK */ - -/** - * Called by a driver when its link goes up - */ -void netif_set_link_up(struct netif *netif ) -{ - if (!(netif->flags & NETIF_FLAG_LINK_UP)) { - netif->flags |= NETIF_FLAG_LINK_UP; - -#if LWIP_DHCP - if (netif->dhcp) { - dhcp_network_changed(netif); - } -#endif /* LWIP_DHCP */ - -#if LWIP_AUTOIP - if (netif->autoip) { - autoip_network_changed(netif); - } -#endif /* LWIP_AUTOIP */ - - if (netif->flags & NETIF_FLAG_UP) { -#if LWIP_ARP - /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ - if (netif->flags & NETIF_FLAG_ETHARP) { - etharp_gratuitous(netif); - } -#endif /* LWIP_ARP */ - -#if LWIP_IGMP - /* resend IGMP memberships */ - if (netif->flags & NETIF_FLAG_IGMP) { - igmp_report_groups( netif); - } -#endif /* LWIP_IGMP */ - } - NETIF_LINK_CALLBACK(netif); - } -} - -/** - * Called by a driver when its link goes down - */ -void netif_set_link_down(struct netif *netif ) -{ - if (netif->flags & NETIF_FLAG_LINK_UP) { - netif->flags &= ~NETIF_FLAG_LINK_UP; - NETIF_LINK_CALLBACK(netif); - } -} - -#if LWIP_NETIF_LINK_CALLBACK -/** - * Set callback to be called when link is brought up/down - */ -void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback) -{ - if (netif) { - netif->link_callback = link_callback; - } -} -#endif /* LWIP_NETIF_LINK_CALLBACK */ - -#if ENABLE_LOOPBACK -/** - * Send an IP packet to be received on the same netif (loopif-like). - * The pbuf is simply copied and handed back to netif->input. - * In multithreaded mode, this is done directly since netif->input must put - * the packet on a queue. - * In callback mode, the packet is put on an internal queue and is fed to - * netif->input by netif_poll(). - * - * @param netif the lwip network interface structure - * @param p the (IP) packet to 'send' - * @param ipaddr the ip address to send the packet to (not used) - * @return ERR_OK if the packet has been sent - * ERR_MEM if the pbuf used to copy the packet couldn't be allocated - */ -err_t -netif_loop_output(struct netif *netif, struct pbuf *p, - ip_addr_t *ipaddr) -{ - struct pbuf *r; - err_t err; - struct pbuf *last; -#if LWIP_LOOPBACK_MAX_PBUFS - u8_t clen = 0; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - /* If we have a loopif, SNMP counters are adjusted for it, - * if not they are adjusted for 'netif'. */ -#if LWIP_SNMP -#if LWIP_HAVE_LOOPIF - struct netif *stats_if = &loop_netif; -#else /* LWIP_HAVE_LOOPIF */ - struct netif *stats_if = netif; -#endif /* LWIP_HAVE_LOOPIF */ -#endif /* LWIP_SNMP */ - SYS_ARCH_DECL_PROTECT(lev); - LWIP_UNUSED_ARG(ipaddr); - - /* Allocate a new pbuf */ - r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); - if (r == NULL) { - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.drop); - snmp_inc_ifoutdiscards(stats_if); - return ERR_MEM; - } -#if LWIP_LOOPBACK_MAX_PBUFS - clen = pbuf_clen(r); - /* check for overflow or too many pbuf on queue */ - if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || - ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { - pbuf_free(r); - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.drop); - snmp_inc_ifoutdiscards(stats_if); - return ERR_MEM; - } - netif->loop_cnt_current += clen; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - - /* Copy the whole pbuf queue p into the single pbuf r */ - if ((err = pbuf_copy(r, p)) != ERR_OK) { - pbuf_free(r); - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.drop); - snmp_inc_ifoutdiscards(stats_if); - return err; - } - - /* Put the packet on a linked list which gets emptied through calling - netif_poll(). */ - - /* let last point to the last pbuf in chain r */ - for (last = r; last->next != NULL; last = last->next); - - SYS_ARCH_PROTECT(lev); - if(netif->loop_first != NULL) { - LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); - netif->loop_last->next = r; - netif->loop_last = last; - } else { - netif->loop_first = r; - netif->loop_last = last; - } - SYS_ARCH_UNPROTECT(lev); - - LINK_STATS_INC(link.xmit); - snmp_add_ifoutoctets(stats_if, p->tot_len); - snmp_inc_ifoutucastpkts(stats_if); - -#if LWIP_NETIF_LOOPBACK_MULTITHREADING - /* For multithreading environment, schedule a call to netif_poll */ - tcpip_callback((tcpip_callback_fn)netif_poll, netif); -#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ - - return ERR_OK; -} - -/** - * Call netif_poll() in the main loop of your application. This is to prevent - * reentering non-reentrant functions like tcp_input(). Packets passed to - * netif_loop_output() are put on a list that is passed to netif->input() by - * netif_poll(). - */ -void -netif_poll(struct netif *netif) -{ - struct pbuf *in; - /* If we have a loopif, SNMP counters are adjusted for it, - * if not they are adjusted for 'netif'. */ -#if LWIP_SNMP -#if LWIP_HAVE_LOOPIF - struct netif *stats_if = &loop_netif; -#else /* LWIP_HAVE_LOOPIF */ - struct netif *stats_if = netif; -#endif /* LWIP_HAVE_LOOPIF */ -#endif /* LWIP_SNMP */ - SYS_ARCH_DECL_PROTECT(lev); - - do { - /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ - SYS_ARCH_PROTECT(lev); - in = netif->loop_first; - if (in != NULL) { - struct pbuf *in_end = in; -#if LWIP_LOOPBACK_MAX_PBUFS - u8_t clen = pbuf_clen(in); - /* adjust the number of pbufs on queue */ - LWIP_ASSERT("netif->loop_cnt_current underflow", - ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); - netif->loop_cnt_current -= clen; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - while (in_end->len != in_end->tot_len) { - LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); - in_end = in_end->next; - } - /* 'in_end' now points to the last pbuf from 'in' */ - if (in_end == netif->loop_last) { - /* this was the last pbuf in the list */ - netif->loop_first = netif->loop_last = NULL; - } else { - /* pop the pbuf off the list */ - netif->loop_first = in_end->next; - LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); - } - /* De-queue the pbuf from its successors on the 'loop_' list. */ - in_end->next = NULL; - } - SYS_ARCH_UNPROTECT(lev); - - if (in != NULL) { - LINK_STATS_INC(link.recv); - snmp_add_ifinoctets(stats_if, in->tot_len); - snmp_inc_ifinucastpkts(stats_if); - /* loopback packets are always IP packets! */ - if (ip_input(in, netif) != ERR_OK) { - pbuf_free(in); - } - /* Don't reference the packet any more! */ - in = NULL; - } - /* go on while there is a packet on the list */ - } while (netif->loop_first != NULL); -} - -#if !LWIP_NETIF_LOOPBACK_MULTITHREADING -/** - * Calls netif_poll() for every netif on the netif_list. - */ -void -netif_poll_all(void) -{ - struct netif *netif = netif_list; - /* loop through netifs */ - while (netif != NULL) { - netif_poll(netif); - /* proceed to next network interface */ - netif = netif->next; - } -} -#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ -#endif /* ENABLE_LOOPBACK */ diff --git a/tools/sdk/lwip/src/core/pbuf.c b/tools/sdk/lwip/src/core/pbuf.c deleted file mode 100644 index 61967840d..000000000 --- a/tools/sdk/lwip/src/core/pbuf.c +++ /dev/null @@ -1,1257 +0,0 @@ -/** - * @file - * Packet buffer management - * - * Packets are built from the pbuf data structure. It supports dynamic - * memory allocation for packet contents or can reference externally - * managed packet contents both in RAM and ROM. Quick allocation for - * incoming packets is provided through pools with fixed sized pbufs. - * - * A packet may span over multiple pbufs, chained as a singly linked - * list. This is called a "pbuf chain". - * - * 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. - * - * 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 - * pbuf of a packet has a ->next field other than NULL, more packets - * are on the queue. - * - * Therefore, looping through a pbuf of a single packet, has an - * loop end condition (tot_len == p->len), NOT (next == NULL). - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" - -#include "lwip/stats.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/pbuf.h" -#include "lwip/sys.h" -#include "arch/perf.h" -#if TCP_QUEUE_OOSEQ -#include "lwip/tcp_impl.h" -#endif -#if LWIP_CHECKSUM_ON_COPY -#include "lwip/inet_chksum.h" -#endif - -#include - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -#ifdef EBUF_LWIP -#define EP_OFFSET 36 -#else -#define EP_OFFSET 0 -#endif /* ESF_LWIP */ - -#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) -/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically - aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ -#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) - -/** - * Attempt to reclaim some memory from queued out-of-sequence TCP segments - * if we run out of pool pbufs. It's better to give priority to new packets - * if we're running out. - */ -#if TCP_QUEUE_OOSEQ -void ICACHE_FLASH_ATTR -pbuf_free_ooseq_new(void* arg) -{ - struct tcp_pcb* pcb; - struct tcp_seg *head = NULL; - struct tcp_seg *seg1 = NULL; - struct tcp_seg *seg2 = NULL; - for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { - head = pcb->ooseq; - seg1 = head; - if (head != NULL) { - if (seg1->next == NULL){ - head = head->next; - tcp_seg_free(seg1); - pcb->ooseq = head; - } else { - while (seg1 != NULL){ - seg2 = seg1; - seg2 = seg2->next; - if (seg2 ->next == NULL){ - seg1->next = seg2->next; - tcp_seg_free(seg2); - break; - } - seg1 = seg1->next; - } - pcb->ooseq = head; - } - } - } -} -#endif - -#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS -#define PBUF_POOL_IS_EMPTY() -#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */ -/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */ -#ifndef PBUF_POOL_FREE_OOSEQ -#define PBUF_POOL_FREE_OOSEQ 1 -#endif /* PBUF_POOL_FREE_OOSEQ */ - -#if PBUF_POOL_FREE_OOSEQ -#include "lwip/tcpip.h" -#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty() -static u8_t pbuf_free_ooseq_queued; -/** - * Attempt to reclaim some memory from queued out-of-sequence TCP segments - * if we run out of pool pbufs. It's better to give priority to new packets - * if we're running out. - * - * This must be done in the correct thread context therefore this function - * can only be used with NO_SYS=0 and through tcpip_callback. - */ -static void ICACHE_FLASH_ATTR -pbuf_free_ooseq(void* arg) -{ - struct tcp_pcb* pcb; - SYS_ARCH_DECL_PROTECT(old_level); - LWIP_UNUSED_ARG(arg); - - SYS_ARCH_PROTECT(old_level); - pbuf_free_ooseq_queued = 0; - SYS_ARCH_UNPROTECT(old_level); - - for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { - if (NULL != pcb->ooseq) { - /** Free the ooseq pbufs of one PCB only */ - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n")); - tcp_segs_free(pcb->ooseq); - pcb->ooseq = NULL; - return; - } - } -} - -/** Queue a call to pbuf_free_ooseq if not already queued. */ -static void ICACHE_FLASH_ATTR -pbuf_pool_is_empty(void) -{ - u8_t queued; - SYS_ARCH_DECL_PROTECT(old_level); - - SYS_ARCH_PROTECT(old_level); - queued = pbuf_free_ooseq_queued; - pbuf_free_ooseq_queued = 1; - SYS_ARCH_UNPROTECT(old_level); - - if(!queued) { - /* queue a call to pbuf_free_ooseq if not already queued */ - if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) { - SYS_ARCH_PROTECT(old_level); - pbuf_free_ooseq_queued = 0; - SYS_ARCH_UNPROTECT(old_level); - } - } -} -#endif /* PBUF_POOL_FREE_OOSEQ */ -#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */ - -/** - * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). - * - * The actual memory allocated for the pbuf is determined by the - * layer at which the pbuf is allocated and the requested size - * (from the size parameter). - * - * @param layer flag to define header size - * @param length size of the pbuf's payload - * @param type this parameter decides how and where the pbuf - * should be allocated as follows: - * - * - PBUF_RAM: buffer memory for pbuf is allocated as one large - * chunk. This includes protocol headers as well. - * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for - * protocol headers. Additional headers must be prepended - * by allocating another pbuf and chain in to the front of - * the ROM pbuf. It is assumed that the memory used is really - * similar to ROM in that it is immutable and will not be - * changed. Memory which is dynamic should generally not - * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. - * - PBUF_REF: no buffer memory is allocated for the pbuf, even for - * protocol headers. It is assumed that the pbuf is only - * being used in a single thread. If the pbuf gets queued, - * then pbuf_take should be called to copy the buffer. - * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from - * the pbuf pool that is allocated during pbuf_init(). - * - * @return the allocated pbuf. If multiple pbufs where allocated, this - * is the first pbuf of a pbuf chain. - */ -struct pbuf * -pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) -{ - struct pbuf *p, *q, *r; - u16_t offset; - s32_t rem_len; /* remaining length */ - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); - - /* determine header offset */ - offset = 0; - switch (layer) { - case PBUF_TRANSPORT: - /* add room for transport (often TCP) layer header */ - offset += PBUF_TRANSPORT_HLEN; - /* FALLTHROUGH */ - case PBUF_IP: - /* add room for IP layer header */ - offset += PBUF_IP_HLEN; - /* FALLTHROUGH */ - case PBUF_LINK: - /* add room for link layer header */ - offset += PBUF_LINK_HLEN; - -#ifdef PBUF_RSV_FOR_WLAN - /* - * 1. LINK_HLEN 14Byte will be remove in WLAN layer - * 2. IEEE80211_HDR_MAX_LEN needs 40 bytes. - * 3. encryption needs exra 4 bytes ahead of actual data payload, and require - * DAddr and SAddr to be 4-byte aligned. - * 4. TRANSPORT and IP are all 20, 4 bytes aligned, nice... - * 5. LCC add 6 bytes more, We don't consider WAPI yet... - * 6. define LWIP_MEM_ALIGN to be 4 Byte aligned, pbuf struct is 16B, Only thing may be - * matter is ether_hdr is not 4B aligned. - * - * So, we need extra (40 + 4 - 14) = 30 and it's happen to be 4-Byte aligned - * - * 1. lwip - * | empty 30B | eth_hdr (14B) | payload ...| - * total: 44B ahead payload - * 2. net80211 - * | max 80211 hdr, 32B | ccmp/tkip iv (8B) | sec rsv(4B) | payload ...| - * total: 40B ahead sec_rsv and 44B ahead payload - * - */ - offset += EP_OFFSET; //remove LINK hdr in wlan -#endif /* PBUF_RSV_FOR_WLAN */ - - break; - case PBUF_RAW: -#ifdef PBUF_RSV_FOR_WLAN - /* - * RAW pbuf suppose - */ - offset += EP_OFFSET; //remove LINK hdr in wlan -#endif /* PBUF_RAW */ - break; - default: - LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); - return NULL; - } - - switch (type) { - case PBUF_POOL: - /* allocate head of pbuf chain into p */ - p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); - if (p == NULL) { - PBUF_POOL_IS_EMPTY(); - return NULL; - } - p->type = type; - p->next = NULL; - - /* make the payload pointer point 'offset' bytes into pbuf data memory */ - p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset))); - LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", - ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); - /* the total length of the pbuf chain is the requested size */ - p->tot_len = length; - /* set the length of the first pbuf in the chain */ - p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)); - LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", - ((u8_t*)p->payload + p->len <= - (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); - LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", - (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); - /* set reference count (needed here in case we fail) */ - p->ref = 1; - - /* now allocate the tail of the pbuf chain */ - - /* remember first pbuf for linkage in next iteration */ - r = p; - /* remaining length to be allocated */ - rem_len = length - p->len; - /* any remaining pbufs to be allocated? */ - while (rem_len > 0) { - q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); - if (q == NULL) { - PBUF_POOL_IS_EMPTY(); - /* free chain so far allocated */ - pbuf_free(p); - /* bail out unsuccesfully */ - return NULL; - } - q->type = type; - q->flags = 0; - q->next = NULL; - /* make previous pbuf point to this pbuf */ - r->next = q; - /* set total length of this pbuf and next in chain */ - LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff); - q->tot_len = (u16_t)rem_len; - /* this pbuf length is pool size, unless smaller sized tail */ - q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED); - q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF); - LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", - ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); - LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", - ((u8_t*)p->payload + p->len <= - (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); - q->ref = 1; - /* calculate remaining length to be allocated */ - rem_len -= q->len; - /* remember this pbuf for linkage in next iteration */ - r = q; - } - /* end of chain */ - /*r->next = NULL;*/ - - break; - case PBUF_RAM: - /* 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; - } - /* Set up internal structure of the pbuf. */ - p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); - p->len = p->tot_len = length; - p->next = NULL; - p->type = type; - p->eb = NULL; - - LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", - ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); - break; -#ifdef EBUF_LWIP - case PBUF_ESF_RX: -#endif /* ESF_LWIP */ - /* pbuf references existing (non-volatile static constant) ROM payload? */ - case PBUF_ROM: - /* pbuf references existing (externally allocated) RAM payload? */ - case PBUF_REF: - /* only allocate memory for the pbuf structure */ - p = (struct pbuf *)memp_malloc(MEMP_PBUF); - if (p == NULL) { - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", - (type == PBUF_ROM) ? "ROM" : "REF")); - return NULL; - } - /* caller must set this field properly, afterwards */ - p->payload = NULL; - p->len = p->tot_len = length; - p->next = NULL; - p->type = type; - break; - default: - LWIP_ASSERT("pbuf_alloc: erroneous type", 0); - return NULL; - } - /* set reference count */ - p->ref = 1; - /* set flags */ - p->flags = 0; - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); - - return p; -} - -#if LWIP_SUPPORT_CUSTOM_PBUF -/** Initialize a custom pbuf (already allocated). - * - * @param layer flag to define header size - * @param length size of the pbuf's payload - * @param type type of the pbuf (only used to treat the pbuf accordingly, as - * this function allocates no memory) - * @param p pointer to the custom pbuf to initialize (already allocated) - * @param payload_mem pointer to the buffer that is used for payload and headers, - * must be at least big enough to hold 'length' plus the header size, - * may be NULL if set later - * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least - * big enough to hold 'length' plus the header size - */ -struct pbuf* -pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p, - void *payload_mem, u16_t payload_mem_len) -{ - u16_t offset; - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length)); - - /* determine header offset */ - offset = 0; - switch (l) { - case PBUF_TRANSPORT: - /* add room for transport (often TCP) layer header */ - offset += PBUF_TRANSPORT_HLEN; - /* FALLTHROUGH */ - case PBUF_IP: - /* add room for IP layer header */ - offset += PBUF_IP_HLEN; - /* FALLTHROUGH */ - case PBUF_LINK: - /* add room for link layer header */ - offset += PBUF_LINK_HLEN; - break; - case PBUF_RAW: - break; - default: - LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0); - return NULL; - } - - if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) { - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length)); - return NULL; - } - - p->pbuf.next = NULL; - if (payload_mem != NULL) { - p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset)); - } else { - p->pbuf.payload = NULL; - } - p->pbuf.flags = PBUF_FLAG_IS_CUSTOM; - p->pbuf.len = p->pbuf.tot_len = length; - p->pbuf.type = type; - p->pbuf.ref = 1; - return &p->pbuf; -} -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ - -/** - * Shrink a pbuf chain to a desired length. - * - * @param p pbuf to shrink. - * @param new_len desired new length of pbuf chain - * - * Depending on the desired length, the first few pbufs in a chain might - * be skipped and left unchanged. The new last pbuf in the chain will be - * resized, and any remaining pbufs will be freed. - * - * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. - * @note May not be called on a packet queue. - * - * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain). - */ -void -pbuf_realloc(struct pbuf *p, u16_t new_len) -{ - struct pbuf *q; - u16_t rem_len; /* remaining length */ - s32_t grow; - - LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); - LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL || - p->type == PBUF_ROM || - p->type == PBUF_RAM || - p->type == PBUF_REF); - - /* desired length larger than current length? */ - if (new_len >= p->tot_len) { - /* enlarging not yet supported */ - return; - } - - /* the pbuf chain grows by (new_len - p->tot_len) bytes - * (which may be negative in case of shrinking) */ - grow = new_len - p->tot_len; - - /* first, step over any pbufs that should remain in the chain */ - rem_len = new_len; - q = p; - /* should this pbuf be kept? */ - while (rem_len > q->len) { - /* decrease remaining length by pbuf length */ - rem_len -= q->len; - /* decrease total length indicator */ - LWIP_ASSERT("grow < max_u16_t", grow < 0xffff); - q->tot_len += (u16_t)grow; - /* proceed to next pbuf in chain */ - q = q->next; - LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); - } - /* we have now reached the new last pbuf (in q) */ - /* rem_len == desired length for pbuf q */ - - /* shrink allocated memory for PBUF_RAM */ - /* (other types merely adjust their length fields */ - if ((q->type == PBUF_RAM) && (rem_len != q->len)) { - /* reallocate and adjust the length of the pbuf that will be split */ - q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len); - LWIP_ASSERT("mem_trim returned q == NULL", q != NULL); - } - /* adjust length fields for new last pbuf */ - q->len = rem_len; - q->tot_len = q->len; - - /* any remaining pbufs in chain? */ - if (q->next != NULL) { - /* free remaining pbufs in chain */ - pbuf_free(q->next); - } - /* q is last packet in chain */ - q->next = NULL; - -} - -/** - * 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 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. - * - */ -u8_t -pbuf_header(struct pbuf *p, s16_t header_size_increment) -{ - u16_t type; - void *payload; - u16_t increment_magnitude; - - LWIP_ASSERT("p != NULL", p != NULL); - if ((header_size_increment == 0) || (p == NULL)) { - return 0; - } - - 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 = 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", - 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", - (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF); -#endif - } - - type = p->type; - /* remember current payload pointer */ - payload = p->payload; - - /* pbuf types containing payloads? */ - if (type == PBUF_RAM || type == PBUF_POOL) { - /* set new payload pointer */ - p->payload = (u8_t *)p->payload - header_size_increment; - /* boundary check fails? */ - if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF + EP_OFFSET) { - LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", - (void *)p->payload, (void *)(p + 1))); - /* restore old payload pointer */ - p->payload = payload; - /* bail out unsuccesfully */ - return 1; - } - /* 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 { - /* cannot expand payload to front (yet!) - * bail out unsuccesfully */ - if (type == PBUF_REF) { - /* increase payload pointer */ - p->payload = (u8_t *)p->payload - header_size_increment; - } else { - return 1; - } - } - } else { - /* Unknown type */ - LWIP_ASSERT("bad pbuf type", 0); - return 1; - } - /* modify pbuf length fields */ - p->len += header_size_increment; - p->tot_len += header_size_increment; - - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n", - (void *)payload, (void *)p->payload, header_size_increment)); - - return 0; -} - -/** - * Dereference a pbuf chain or queue and deallocate any no-longer-used - * pbufs at the head of this chain or queue. - * - * Decrements the pbuf reference count. If it reaches zero, the pbuf is - * deallocated. - * - * For a pbuf chain, this is repeated for each pbuf in the chain, - * up to the first pbuf which has a non-zero reference count after - * decrementing. So, when all reference counts are one, the whole - * chain is free'd. - * - * @param p The pbuf (chain) to be dereferenced. - * - * @return the number of pbufs that were de-allocated - * from the head of the chain. - * - * @note MUST NOT be called on a packet queue (Not verified to work yet). - * @note the reference counter of a pbuf equals the number of pointers - * that refer to the pbuf (or into the pbuf). - * - * @internal examples: - * - * 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 - * 2->1->1 becomes 1->1->1 - * 1->1->1 becomes ....... - * - */ -u8_t -pbuf_free(struct pbuf *p) -{ - u16_t type; - struct pbuf *q; - u8_t count; - - if (p == NULL) { - LWIP_ASSERT("p != NULL", p != NULL); - /* if assertions are disabled, proceed with debug output */ - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("pbuf_free(p == NULL) was called.\n")); - return 0; - } - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p)); - - PERF_START; - - LWIP_ASSERT("pbuf_free: sane type", - p->type == PBUF_RAM || p->type == PBUF_ROM || - p->type == PBUF_REF || p->type == PBUF_POOL -#ifdef EBUF_LWIP - || p->type == PBUF_ESF_RX -#endif //EBUF_LWIP - ); - - count = 0; - /* de-allocate all consecutive pbufs from the head of the chain that - * obtain a zero reference count after decrementing*/ - while (p != NULL) { - u16_t ref; - SYS_ARCH_DECL_PROTECT(old_level); - /* Since decrementing ref cannot be guaranteed to be a single machine operation - * we must protect it. We put the new ref into a local variable to prevent - * further protection. */ - SYS_ARCH_PROTECT(old_level); - /* all pbufs in a chain are referenced at least once */ - LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); - /* decrease reference count (number of pointers to pbuf) */ - ref = --(p->ref); - SYS_ARCH_UNPROTECT(old_level); - /* this pbuf is no longer referenced to? */ - if (ref == 0) { - /* remember next pbuf in chain for next iteration */ - q = p->next; - LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p)); - type = p->type; -#if LWIP_SUPPORT_CUSTOM_PBUF - /* is this a custom pbuf? */ - if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { - struct pbuf_custom *pc = (struct pbuf_custom*)p; - LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); - pc->custom_free_function(p); - } else -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ - { - /* is this a pbuf from the pool? */ - if (type == PBUF_POOL) { - memp_free(MEMP_PBUF_POOL, p); - /* is this a ROM or RAM referencing pbuf? */ - } else if (type == PBUF_ROM || type == PBUF_REF -#ifdef EBUF_LWIP - || type == PBUF_ESF_RX -#endif //EBUF_LWIP - ) { -#ifdef EBUF_LWIP - system_pp_recycle_rx_pkt(p->eb); -#endif //EBUF_LWIP - memp_free(MEMP_PBUF, p); - /* type == PBUF_RAM */ - } else { - mem_free(p); - } - } - count++; - /* proceed to next pbuf */ - p = q; - /* p->ref > 0, this pbuf is still referenced to */ - /* (and so the remaining pbufs in chain as well) */ - } else { - LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref)); - /* stop walking through the chain */ - p = NULL; - } - } - PERF_STOP("pbuf_free"); - /* return number of de-allocated pbufs */ - return count; -} - -/** - * Count number of pbufs in a chain - * - * @param p first pbuf of chain - * @return the number of pbufs in a chain - */ - -u8_t -pbuf_clen(struct pbuf *p) -{ - u8_t len; - - len = 0; - while (p != NULL) { - ++len; - p = p->next; - } - return len; -} - -/** - * Increment the reference count of the pbuf. - * - * @param p pbuf to increase reference counter of - * - */ -void -pbuf_ref(struct pbuf *p) -{ - SYS_ARCH_DECL_PROTECT(old_level); - /* pbuf given? */ - if (p != NULL) { - SYS_ARCH_PROTECT(old_level); - ++(p->ref); - SYS_ARCH_UNPROTECT(old_level); - } -} - -/** - * 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) -{ - struct pbuf *p; - - LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", - ((h != NULL) && (t != NULL)), return;); - - /* proceed to last pbuf of chain */ - for (p = h; p->next != NULL; p = p->next) { - /* add total length of second chain to all totals of first chain */ - p->tot_len += t->tot_len; - } - /* { p is last pbuf of first h chain, p->next == NULL } */ - LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); - LWIP_ASSERT("p->next == NULL", p->next == NULL); - /* add total length of second chain to last pbuf total of first chain */ - p->tot_len += t->tot_len; - /* chain last pbuf of head (p) with first of tail (t) */ - p->next = t; - /* p->next now references t, but the caller will drop its reference to t, - * so netto there is no change to the reference count of t. - */ -} - -/** - * 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. - * @note MAY NOT be called on a packet queue. - * - * The ->tot_len fields of all pbufs of the head chain are adjusted. - * The ->next field of the last pbuf of the head chain is adjusted. - * The ->ref field of the first pbuf of the tail chain is adjusted. - * - */ -void -pbuf_chain(struct pbuf *h, struct pbuf *t) -{ - pbuf_cat(h, t); - /* t is now referenced by h */ - pbuf_ref(t); - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); -} - -/** - * Dechains the first pbuf from its succeeding pbufs in the chain. - * - * Makes p->tot_len field equal to p->len. - * @param p pbuf to dechain - * @return remainder of the pbuf chain, or NULL if it was de-allocated. - * @note May not be called on a packet queue. - */ -struct pbuf * -pbuf_dechain(struct pbuf *p) -{ - struct pbuf *q; - u8_t tail_gone = 1; - /* tail */ - q = p->next; - /* pbuf has successor in chain? */ - if (q != NULL) { - /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ - LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); - /* enforce invariant if assertion is disabled */ - q->tot_len = p->tot_len - p->len; - /* decouple pbuf from remainder */ - p->next = NULL; - /* total length of pbuf p is its own length only */ - p->tot_len = p->len; - /* q is no longer referenced by p, free it */ - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); - tail_gone = pbuf_free(q); - if (tail_gone > 0) { - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, - ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); - } - /* return remaining tail or NULL if deallocated */ - } - /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ - LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); - return ((tail_gone > 0) ? NULL : q); -} - -/** - * - * Create PBUF_RAM copies of pbufs. - * - * Used to queue packets on behalf of the lwIP stack, such as - * ARP based queueing. - * - * @note You MUST explicitly use p = pbuf_take(p); - * - * @note Only one packet is copied, no packet queue! - * - * @param p_to pbuf destination of the copy - * @param p_from pbuf source of the copy - * - * @return ERR_OK if pbuf was copied - * ERR_ARG if one of the pbufs is NULL or p_to is not big - * enough to hold p_from - */ -err_t -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", - (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) && - (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); - - /* iterate through pbuf chain */ - do - { - LWIP_ASSERT("p_to != NULL", p_to != NULL); - /* copy one part of the original chain */ - if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { - /* complete current p_from fits into current p_to */ - len = p_from->len - offset_from; - } else { - /* current p_from does not fit into current p_to */ - len = p_to->len - offset_to; - } - MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len); - offset_to += len; - offset_from += len; - LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); - if (offset_to == p_to->len) { - /* on to next p_to (if any) */ - offset_to = 0; - p_to = p_to->next; - } - LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); - if (offset_from >= p_from->len) { - /* on to next p_from (if any) */ - offset_from = 0; - p_from = p_from->next; - } - - 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!\n", - (p_from->next == NULL), return ERR_VAL;); - } - 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!\n", - (p_to->next == NULL), return ERR_VAL;); - } - } while (p_from); - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n")); - return ERR_OK; -} - -/** - * 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 - * than buf->tot_len will be copied, irrespective of len - * @param offset offset into the packet buffer from where to begin copying len bytes - * @return the number of bytes copied, or 0 on failure - */ -u16_t -pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) -{ - struct pbuf *p; - u16_t left; - u16_t buf_copy_len; - u16_t copied_total = 0; - - LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); - LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); - - left = 0; - - 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) { - 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; - /* copy the necessary parts of the buffer */ - MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); - copied_total += buf_copy_len; - left += buf_copy_len; - len -= buf_copy_len; - offset = 0; - } - } - return copied_total; -} - -/** - * Copy application supplied data into a pbuf. - * This function can only be used to copy the equivalent of buf->tot_len data. - * - * @param buf pbuf to fill with data - * @param dataptr application supplied data buffer - * @param len length of the application supplied data buffer - * - * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough - */ -err_t -pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) -{ - struct pbuf *p; - u16_t buf_copy_len; - u16_t total_copy_len = len; - u16_t copied_total = 0; - - LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;); - LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;); - - if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { - return ERR_ARG; - } - - /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ - for(p = buf; total_copy_len != 0; p = p->next) { - LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL); - buf_copy_len = total_copy_len; - if (buf_copy_len > p->len) { - /* this pbuf cannot hold all remaining data */ - buf_copy_len = p->len; - } - /* copy the necessary parts of the buffer */ - MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len); - total_copy_len -= buf_copy_len; - copied_total += buf_copy_len; - } - LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len); - return ERR_OK; -} - -/** - * Creates a single pbuf out of a queue of pbufs. - * - * @remark: Either the source pbuf 'p' is freed by this function or the original - * pbuf 'p' is returned, therefore the caller has to check the result! - * - * @param p the source pbuf - * @param layer pbuf_layer of the new pbuf - * - * @return a new, single pbuf (p->next is NULL) - * or the old pbuf if allocation fails - */ -struct pbuf* -pbuf_coalesce(struct pbuf *p, pbuf_layer layer) -{ - struct pbuf *q; - err_t err; - if (p->next == NULL) { - return p; - } - q = pbuf_alloc(layer, p->tot_len, PBUF_RAM); - if (q == NULL) { - /* @todo: what do we do now? */ - return p; - } - err = pbuf_copy(q, p); - LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); - pbuf_free(p); - return q; -} - -#if LWIP_CHECKSUM_ON_COPY -/** - * Copies data into a single pbuf (*not* into a pbuf queue!) and updates - * the checksum while copying - * - * @param p the pbuf to copy data into - * @param start_offset offset of p->payload where to copy the data to - * @param dataptr data to copy into the pbuf - * @param len length of data to copy into the pbuf - * @param chksum pointer to the checksum which is updated - * @return ERR_OK if successful, another error if the data does not fit - * within the (first) pbuf (no pbuf queues!) - */ -err_t -pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, - u16_t len, u16_t *chksum) -{ - u32_t acc; - u16_t copy_chksum; - char *dst_ptr; - LWIP_ASSERT("p != NULL", p != NULL); - LWIP_ASSERT("dataptr != NULL", dataptr != NULL); - LWIP_ASSERT("chksum != NULL", chksum != NULL); - LWIP_ASSERT("len != 0", len != 0); - - if ((start_offset >= p->len) || (start_offset + len > p->len)) { - return ERR_ARG; - } - - dst_ptr = ((char*)p->payload) + start_offset; - copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len); - if ((start_offset & 1) != 0) { - copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum); - } - acc = *chksum; - acc += copy_chksum; - *chksum = FOLD_U32T(acc); - return ERR_OK; -} -#endif /* LWIP_CHECKSUM_ON_COPY */ - - /** Get one byte from the specified position in a pbuf - * WARNING: returns zero for offset >= p->tot_len - * - * @param p pbuf to parse - * @param offset offset into p of the byte to return - * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len - */ -u8_t -pbuf_get_at(struct pbuf* p, u16_t offset) -{ - u16_t copy_from = offset; - struct pbuf* q = p; - - /* get the correct pbuf */ - while ((q != NULL) && (q->len <= copy_from)) { - copy_from -= q->len; - q = q->next; - } - /* return requested data if pbuf is OK */ - if ((q != NULL) && (q->len > copy_from)) { - return ((u8_t*)q->payload)[copy_from]; - } - return 0; -} - -/** Compare pbuf contents at specified offset with memory s2, both of length n - * - * @param p pbuf to compare - * @param offset offset into p at wich to start comparing - * @param s2 buffer to compare - * @param n length of buffer to compare - * @return zero if equal, nonzero otherwise - * (0xffff if p is too short, diffoffset+1 otherwise) - */ -u16_t -pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n) -{ - u16_t start = offset; - struct pbuf* q = p; - - /* get the correct pbuf */ - while ((q != NULL) && (q->len <= start)) { - start -= q->len; - q = q->next; - } - /* return requested data if pbuf is OK */ - if ((q != NULL) && (q->len > start)) { - u16_t i; - for(i = 0; i < n; i++) { - u8_t a = pbuf_get_at(q, start + i); - u8_t b = ((u8_t*)s2)[i]; - if (a != b) { - return i+1; - } - } - return 0; - } - return 0xffff; -} - -/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset - * start_offset. - * - * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as - * return value 'not found' - * @param mem search for the contents of this buffer - * @param mem_len length of 'mem' - * @param start_offset offset into p at which to start searching - * @return 0xFFFF if substr was not found in p or the index where it was found - */ -u16_t -pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset) -{ - u16_t i; - u16_t max = p->tot_len - mem_len; - if (p->tot_len >= mem_len + start_offset) { - for(i = start_offset; i <= max; ) { - u16_t plus = pbuf_memcmp(p, i, mem, mem_len); - if (plus == 0) { - return i; - } else { - i += plus; - } - } - } - return 0xFFFF; -} - -/** Find occurrence of substr with length substr_len in pbuf p, start at offset - * start_offset - * WARNING: in contrast to strstr(), this one does not stop at the first \0 in - * the pbuf/source string! - * - * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as - * return value 'not found' - * @param substr string to search for in p, maximum length is 0xFFFE - * @return 0xFFFF if substr was not found in p or the index where it was found - */ -u16_t -pbuf_strstr(struct pbuf* p, const char* substr) -{ - size_t substr_len; - if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) { - return 0xFFFF; - } - substr_len = os_strlen(substr); - if (substr_len >= 0xFFFF) { - return 0xFFFF; - } - return pbuf_memfind(p, substr, (u16_t)substr_len, 0); -} diff --git a/tools/sdk/lwip/src/core/raw.c b/tools/sdk/lwip/src/core/raw.c deleted file mode 100644 index b89a4f82f..000000000 --- a/tools/sdk/lwip/src/core/raw.c +++ /dev/null @@ -1,358 +0,0 @@ -/** - * @file - * Implementation of raw protocol PCBs for low-level handling of - * different types of protocols besides (or overriding) those - * already available in lwIP. - * - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" - -#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/def.h" -#include "lwip/memp.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/raw.h" -#include "lwip/stats.h" -#include "arch/perf.h" - -#include - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -/** The list of RAW PCBs */ -static struct raw_pcb *raw_pcbs; - -/** - * Determine if in incoming IP packet is covered by a RAW PCB - * and if so, pass it to a user-provided receive callback function. - * - * Given an incoming IP datagram (as a chain of pbufs) this function - * finds a corresponding RAW PCB and calls the corresponding receive - * callback function. - * - * @param p pbuf to be demultiplexed to a RAW PCB. - * @param inp network interface on which the datagram was received. - * @return - 1 if the packet has been eaten by a RAW PCB receive - * callback function. The caller MAY NOT not reference the - * packet any longer, and MAY NOT call pbuf_free(). - * @return - 0 if packet is not eaten (pbuf is still referenced by the - * caller). - * - */ -u8_t ICACHE_FLASH_ATTR -raw_input(struct pbuf *p, struct netif *inp) -{ - struct raw_pcb *pcb, *prev; - struct ip_hdr *iphdr; - s16_t proto; - u8_t eaten = 0; - - LWIP_UNUSED_ARG(inp); - - iphdr = (struct ip_hdr *)p->payload; - proto = IPH_PROTO(iphdr); - - prev = NULL; - pcb = raw_pcbs; - /* loop through all raw pcbs until the packet is eaten by one */ - /* this allows multiple pcbs to match against the packet by design */ - while ((eaten == 0) && (pcb != NULL)) { - if ((pcb->protocol == proto) && - (ip_addr_isany(&pcb->local_ip) || - ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest))) { -#if IP_SOF_BROADCAST_RECV - /* broadcast filter? */ - if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(¤t_iphdr_dest, inp)) -#endif /* IP_SOF_BROADCAST_RECV */ - { - /* receive callback function available? */ - if (pcb->recv != NULL) { - /* the receive callback function did not eat the packet? */ - if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) { - /* receive function ate the packet */ - p = NULL; - eaten = 1; - if (prev != NULL) { - /* move the pcb to the front of raw_pcbs so that is - found faster next time */ - prev->next = pcb->next; - pcb->next = raw_pcbs; - raw_pcbs = pcb; - } - } - } - /* no receive callback function was set for this raw PCB */ - } - /* drop the packet */ - } - prev = pcb; - pcb = pcb->next; - } - return eaten; -} - -/** - * Bind a RAW PCB. - * - * @param pcb RAW PCB to be bound with a local address ipaddr. - * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to - * bind to all local interfaces. - * - * @return lwIP error code. - * - ERR_OK. Successful. No error occured. - * - ERR_USE. The specified IP address is already bound to by - * another RAW PCB. - * - * @see raw_disconnect() - */ -err_t ICACHE_FLASH_ATTR -raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr) -{ - ip_addr_set(&pcb->local_ip, ipaddr); - return ERR_OK; -} - -/** - * Connect an RAW PCB. This function is required by upper layers - * of lwip. Using the raw api you could use raw_sendto() instead - * - * This will associate the RAW PCB with the remote address. - * - * @param pcb RAW PCB to be connected with remote address ipaddr and port. - * @param ipaddr remote IP address to connect with. - * - * @return lwIP error code - * - * @see raw_disconnect() and raw_sendto() - */ -err_t ICACHE_FLASH_ATTR -raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr) -{ - ip_addr_set(&pcb->remote_ip, ipaddr); - return ERR_OK; -} - - -/** - * Set the callback function for received packets that match the - * raw PCB's protocol and binding. - * - * The callback function MUST either - * - eat the packet by calling pbuf_free() and returning non-zero. The - * packet will not be passed to other raw PCBs or other protocol layers. - * - not free the packet, and return zero. The packet will be matched - * against further PCBs and/or forwarded to another protocol layers. - * - * @return non-zero if the packet was free()d, zero if the packet remains - * available for others. - */ -void ICACHE_FLASH_ATTR -raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) -{ - /* remember recv() callback and user data */ - pcb->recv = recv; - pcb->recv_arg = recv_arg; -} - -/** - * Send the raw IP packet to the given address. Note that actually you cannot - * modify the IP headers (this is inconsistent with the receive callback where - * you actually get the IP headers), you can only specify the IP payload here. - * It requires some more changes in lwIP. (there will be a raw_send() function - * then.) - * - * @param pcb the raw pcb which to send - * @param p the IP payload to send - * @param ipaddr the destination address of the IP packet - * - */ -err_t ICACHE_FLASH_ATTR -raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) -{ - err_t err; - struct netif *netif; - ip_addr_t *src_ip; - struct pbuf *q; /* q will be sent down the stack */ - - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); - - /* not enough space to add an IP header to first pbuf in given p chain? */ - if (pbuf_header(p, IP_HLEN)) { - /* allocate header in new pbuf */ - q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); - /* new header pbuf could not be allocated? */ - if (q == NULL) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); - return ERR_MEM; - } - if (p->tot_len != 0) { - /* chain header q in front of given pbuf p */ - pbuf_chain(q, p); - } - /* { first pbuf q points to header pbuf } */ - LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); - } else { - /* first pbuf q equals given pbuf */ - q = p; - if(pbuf_header(q, -IP_HLEN)) { - LWIP_ASSERT("Can't restore header we just removed!", 0); - return ERR_MEM; - } - } - - if ((netif = ip_route(ipaddr)) == NULL) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); - /* free any temporary header pbuf allocated by pbuf_header() */ - if (q != p) { - pbuf_free(q); - } - return ERR_RTE; - } - -#if IP_SOF_BROADCAST - /* broadcast filter? */ - if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); - /* free any temporary header pbuf allocated by pbuf_header() */ - if (q != p) { - pbuf_free(q); - } - return ERR_VAL; - } -#endif /* IP_SOF_BROADCAST */ - - if (ip_addr_isany(&pcb->local_ip)) { - /* use outgoing network interface IP address as source address */ - src_ip = &(netif->ip_addr); - } else { - /* use RAW PCB local IP address as source address */ - src_ip = &(pcb->local_ip); - } - -#if LWIP_NETIF_HWADDRHINT - netif->addr_hint = &(pcb->addr_hint); -#endif /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); -#if LWIP_NETIF_HWADDRHINT - netif->addr_hint = NULL; -#endif /* LWIP_NETIF_HWADDRHINT*/ - - /* did we chain a header earlier? */ - if (q != p) { - /* free the header */ - pbuf_free(q); - } - return err; -} - -/** - * Send the raw IP packet to the address given by raw_connect() - * - * @param pcb the raw pcb which to send - * @param p the IP payload to send - * - */ -err_t ICACHE_FLASH_ATTR -raw_send(struct raw_pcb *pcb, struct pbuf *p) -{ - return raw_sendto(pcb, p, &pcb->remote_ip); -} - -/** - * Remove an RAW PCB. - * - * @param pcb RAW PCB to be removed. The PCB is removed from the list of - * RAW PCB's and the data structure is freed from memory. - * - * @see raw_new() - */ -void ICACHE_FLASH_ATTR -raw_remove(struct raw_pcb *pcb) -{ - struct raw_pcb *pcb2; - /* pcb to be removed is first in list? */ - if (raw_pcbs == pcb) { - /* make list start at 2nd pcb */ - raw_pcbs = raw_pcbs->next; - /* pcb not 1st in list */ - } else { - for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { - /* find pcb in raw_pcbs list */ - if (pcb2->next != NULL && pcb2->next == pcb) { - /* remove pcb from list */ - pcb2->next = pcb->next; - } - } - } - memp_free(MEMP_RAW_PCB, pcb); -} - -/** - * Create a RAW PCB. - * - * @return The RAW PCB which was created. NULL if the PCB data structure - * could not be allocated. - * - * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP) - * - * @see raw_remove() - */ -struct raw_pcb * ICACHE_FLASH_ATTR -raw_new(u8_t proto) -{ - struct raw_pcb *pcb; - - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n")); - - pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB); - /* could allocate RAW PCB? */ - if (pcb != NULL) { - /* initialize PCB to all zeroes */ - os_memset(pcb, 0, sizeof(struct raw_pcb)); - pcb->protocol = proto; - pcb->ttl = RAW_TTL; - pcb->next = raw_pcbs; - raw_pcbs = pcb; - } - return pcb; -} - -#endif /* LWIP_RAW */ diff --git a/tools/sdk/lwip/src/core/sntp.c b/tools/sdk/lwip/src/core/sntp.c deleted file mode 100755 index 0aa26b91c..000000000 --- a/tools/sdk/lwip/src/core/sntp.c +++ /dev/null @@ -1,1185 +0,0 @@ -/** - * @file - * SNTP client module - * - * 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 - * - support broadcast/multicast mode? - */ - -/* - * 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 (lwIP raw API part) - */ - -#include "lwip/sntp.h" -#include "osapi.h" -#include "os_type.h" -#include "lwip/opt.h" -#include "lwip/timers.h" -#include "lwip/udp.h" -#include "lwip/dns.h" -#include "lwip/ip_addr.h" -#include "lwip/pbuf.h" -#include "lwip/app/time.h" -//#include -#if LWIP_UDP - -/** - * SNTP_DEBUG: Enable debugging for SNTP. - */ -#ifndef SNTP_DEBUG -#define SNTP_DEBUG LWIP_DBG_ON -#endif - -/** SNTP server port */ -#ifndef SNTP_PORT -#define SNTP_PORT 123 -#endif - -/** Set this to 1 to allow config of SNTP server(s) by DNS name */ -#ifndef SNTP_SERVER_DNS -#define SNTP_SERVER_DNS 0 -#endif - -/** Handle support for more than one server via NTP_MAX_SERVERS, - * but catch legacy style of setting SNTP_SUPPORT_MULTIPLE_SERVERS, probably outside of this file - */ -#ifndef SNTP_SUPPORT_MULTIPLE_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 */ -#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ -/* The developer has defined SNTP_SUPPORT_MULTIPLE_SERVERS, probably from old code */ -#if SNTP_MAX_SERVERS <= 1 -#error "SNTP_MAX_SERVERS needs to be defined to the max amount of servers if SNTP_SUPPORT_MULTIPLE_SERVERS is defined" -#endif /* SNTP_MAX_SERVERS <= 1 */ -#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ - - -/** Sanity check: - * Define this to - * - 0 to turn off sanity checks (default; smaller code) - * - >= 1 to check address and port of the response packet to ensure the - * response comes from the server we sent the request to. - * - >= 2 to check returned Originate Timestamp against Transmit Timestamp - * sent to the server (to ensure response to older request). - * - >= 3 @todo: discard reply if any of the LI, Stratum, or Transmit Timestamp - * fields is 0 or the Mode field is not 4 (unicast) or 5 (broadcast). - * - >= 4 @todo: to check that the Root Delay and Root Dispersion fields are each - * greater than or equal to 0 and less than infinity, where infinity is - * currently a cozy number like one second. This check avoids using a - * server whose synchronization source has expired for a very long time. - */ -#ifndef SNTP_CHECK_RESPONSE -#define SNTP_CHECK_RESPONSE 0 -#endif - -/** According to the RFC, this shall be a random delay - * between 1 and 5 minutes (in milliseconds) to prevent load peaks. - * This can be defined to a random generation function, - * which must return the delay in milliseconds as u32_t. - * Turned off by default. - */ -#ifndef SNTP_STARTUP_DELAY -#define SNTP_STARTUP_DELAY 0 -#endif - -/** If you want the startup delay to be a function, define this - * to a function (including the brackets) and define SNTP_STARTUP_DELAY to 1. - */ -#ifndef SNTP_STARTUP_DELAY_FUNC -#define SNTP_STARTUP_DELAY_FUNC SNTP_STARTUP_DELAY -#endif - -/** SNTP receive timeout - in milliseconds - * Also used as retry timeout - this shouldn't be too low. - * Default is 3 seconds. - */ -#ifndef SNTP_RECV_TIMEOUT -#define SNTP_RECV_TIMEOUT 3000 -#endif - -/** SNTP update delay - in milliseconds - * Default is 1 hour. - */ -#ifndef SNTP_UPDATE_DELAY -#define SNTP_UPDATE_DELAY 3600000 -#endif -#if (SNTP_UPDATE_DELAY < 15000) && !SNTP_SUPPRESS_DELAY_CHECK -#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds!" -#endif - -/** SNTP macro to change system time and/or the update the RTC clock */ -#ifndef SNTP_SET_SYSTEM_TIME -#define SNTP_SET_SYSTEM_TIME(sec) ((void)sec) -#endif - -/** SNTP macro to change system time including microseconds */ -uint8 sntp_receive_time_size = 1; -#define SNTP_RECEIVE_TIME_SIZE sntp_receive_time_size -#define SNTP_SET_SYSTEM_TIME_US(sec, us) sntp_update_rtc(sec, us) -//#ifdef SNTP_SET_SYSTEM_TIME_US -//#define SNTP_SET_SYSTEM_TIME_US(sec, us) sntp_update_rtc(sec, 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 sntp_receive_time_size -//#endif - -/** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2 - * to send in request and compare in response. - */ -#ifndef SNTP_GET_SYSTEM_TIME -#define SNTP_GET_SYSTEM_TIME(sec, us) do { (sec) = 0; (us) = 0; } while(0) -#endif - -/** Default retry timeout (in milliseconds) if the response - * received is invalid. - * This is doubled with each retry until SNTP_RETRY_TIMEOUT_MAX is reached. - */ -#ifndef SNTP_RETRY_TIMEOUT -#define SNTP_RETRY_TIMEOUT SNTP_RECV_TIMEOUT -#endif - -/** Maximum retry timeout (in milliseconds). */ -#ifndef SNTP_RETRY_TIMEOUT_MAX -#define SNTP_RETRY_TIMEOUT_MAX (SNTP_RETRY_TIMEOUT * 10) -#endif - -/** Increase retry timeout with every retry sent - * Default is on to conform to RFC. - */ -#ifndef SNTP_RETRY_TIMEOUT_EXP -#define SNTP_RETRY_TIMEOUT_EXP 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 */ -#define DIFF_SEC_1900_1970 (2208988800UL) - -/** - * 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 -#define PACK_STRUCT_FLD_8 PACK_STRUCT_FIELD -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 UDP pcb used by the SNTP client */ -static struct udp_pcb* sntp_pcb; - -sint8 time_zone = 8; -/** 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]; - -static u8_t sntp_set_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 */ - -//uint32 current_stamp_1 = 0; -//uint32 current_stamp_2 = 0; -static bool sntp_time_flag = false; -static uint32 sntp_update_delay = SNTP_UPDATE_DELAY; -static uint32 realtime_stamp = 0; -LOCAL os_timer_t sntp_timer; -/*****************************************/ -#define SECSPERMIN 60L -#define MINSPERHOUR 60L -#define HOURSPERDAY 24L -#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) -#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY) -#define DAYSPERWEEK 7 -#define MONSPERYEAR 12 - -#define YEAR_BASE 1900 -#define EPOCH_YEAR 1970 -#define EPOCH_WDAY 4 -#define EPOCH_YEARS_SINCE_LEAP 2 -#define EPOCH_YEARS_SINCE_CENTURY 70 -#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370 - -#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) - -int __tznorth; -int __tzyear; -char reult[100]; -static const int mon_lengths[2][12] = { - {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, - {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} -} ; - -static const int year_lengths[2] = { - 365, - 366 -} ; -struct tm -{ - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; - -struct tm res_buf; -typedef struct __tzrule_struct -{ - char ch; - int m; - int n; - int d; - int s; - time_t change; - int offset; -} __tzrule_type; - -__tzrule_type sntp__tzrule[2]; -struct tm * ICACHE_FLASH_ATTR -sntp_mktm_r(const time_t * tim_p ,struct tm *res ,int is_gmtime) -{ - long days, rem; - time_t lcltime; - int i; - int y; - int yleap; - const int *ip; - - /* base decision about std/dst time on current time */ - lcltime = *tim_p; - - days = ((long)lcltime) / SECSPERDAY; - rem = ((long)lcltime) % SECSPERDAY; - while (rem < 0) - { - rem += SECSPERDAY; - --days; - } - while (rem >= SECSPERDAY) - { - rem -= SECSPERDAY; - ++days; - } - - /* compute hour, min, and sec */ - res->tm_hour = (int) (rem / SECSPERHOUR); - rem %= SECSPERHOUR; - res->tm_min = (int) (rem / SECSPERMIN); - res->tm_sec = (int) (rem % SECSPERMIN); - - /* compute day of week */ - if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) - res->tm_wday += DAYSPERWEEK; - - /* compute year & day of year */ - y = EPOCH_YEAR; - if (days >= 0) - { - for (;;) - { - yleap = isleap(y); - if (days < year_lengths[yleap]) - break; - y++; - days -= year_lengths[yleap]; - } - } - else - { - do - { - --y; - yleap = isleap(y); - days += year_lengths[yleap]; - } while (days < 0); - } - - res->tm_year = y - YEAR_BASE; - res->tm_yday = days; - ip = mon_lengths[yleap]; - for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon) - days -= ip[res->tm_mon]; - res->tm_mday = days + 1; - - if (!is_gmtime) - { - int offset; - int hours, mins, secs; - -// TZ_LOCK; -// if (_daylight) -// { -// if (y == __tzyear || __tzcalc_limits (y)) -// res->tm_isdst = (__tznorth -// ? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change) -// : (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change)); -// else -// res->tm_isdst = -1; -// } -// else - res->tm_isdst = -1; - - offset = (res->tm_isdst == 1 ? sntp__tzrule[1].offset : sntp__tzrule[0].offset); - - hours = offset / SECSPERHOUR; - offset = offset % SECSPERHOUR; - - mins = offset / SECSPERMIN; - secs = offset % SECSPERMIN; - - res->tm_sec -= secs; - res->tm_min -= mins; - res->tm_hour -= hours; - - if (res->tm_sec >= SECSPERMIN) - { - res->tm_min += 1; - res->tm_sec -= SECSPERMIN; - } - else if (res->tm_sec < 0) - { - res->tm_min -= 1; - res->tm_sec += SECSPERMIN; - } - if (res->tm_min >= MINSPERHOUR) - { - res->tm_hour += 1; - res->tm_min -= MINSPERHOUR; - } - else if (res->tm_min < 0) - { - res->tm_hour -= 1; - res->tm_min += MINSPERHOUR; - } - if (res->tm_hour >= HOURSPERDAY) - { - ++res->tm_yday; - ++res->tm_wday; - if (res->tm_wday > 6) - res->tm_wday = 0; - ++res->tm_mday; - res->tm_hour -= HOURSPERDAY; - if (res->tm_mday > ip[res->tm_mon]) - { - res->tm_mday -= ip[res->tm_mon]; - res->tm_mon += 1; - if (res->tm_mon == 12) - { - res->tm_mon = 0; - res->tm_year += 1; - res->tm_yday = 0; - } - } - } - else if (res->tm_hour < 0) - { - res->tm_yday -= 1; - res->tm_wday -= 1; - if (res->tm_wday < 0) - res->tm_wday = 6; - res->tm_mday -= 1; - res->tm_hour += 24; - if (res->tm_mday == 0) - { - res->tm_mon -= 1; - if (res->tm_mon < 0) - { - res->tm_mon = 11; - res->tm_year -= 1; - res->tm_yday = 365 + isleap(res->tm_year); - } - res->tm_mday = ip[res->tm_mon]; - } - } -// TZ_UNLOCK; - } - else - res->tm_isdst = 0; -// os_printf("res %d %d %d %d %d\n",res->tm_year,res->tm_mon,res->tm_mday,res->tm_yday,res->tm_hour); - return (res); -} -struct tm * ICACHE_FLASH_ATTR -sntp_localtime_r(const time_t * tim_p , - struct tm *res) -{ - return sntp_mktm_r (tim_p, res, 0); -} - -struct tm * ICACHE_FLASH_ATTR -sntp_localtime(const time_t * tim_p) -{ - return sntp_localtime_r (tim_p, &res_buf); -} - - -int ICACHE_FLASH_ATTR -sntp__tzcalc_limits(int year) -{ - int days, year_days, years; - int i, j; - - if (year < EPOCH_YEAR) - return 0; - - __tzyear = year; - - years = (year - EPOCH_YEAR); - - year_days = years * 365 + - (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 + - (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400; - - for (i = 0; i < 2; ++i) - { - if (sntp__tzrule[i].ch == 'J') - days = year_days + sntp__tzrule[i].d + (isleap(year) && sntp__tzrule[i].d >= 60); - else if (sntp__tzrule[i].ch == 'D') - days = year_days + sntp__tzrule[i].d; - else - { - int yleap = isleap(year); - int m_day, m_wday, wday_diff; - const int *ip = mon_lengths[yleap]; - - days = year_days; - - for (j = 1; j < sntp__tzrule[i].m; ++j) - days += ip[j-1]; - - m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK; - - wday_diff = sntp__tzrule[i].d - m_wday; - if (wday_diff < 0) - wday_diff += DAYSPERWEEK; - m_day = (sntp__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff; - - while (m_day >= ip[j-1]) - m_day -= DAYSPERWEEK; - - days += m_day; - } - - /* store the change-over time in GMT form by adding offset */ - sntp__tzrule[i].change = days * SECSPERDAY + sntp__tzrule[i].s + sntp__tzrule[i].offset; - } - - __tznorth = (sntp__tzrule[0].change < sntp__tzrule[1].change); - - return 1; -} - -char * ICACHE_FLASH_ATTR -sntp_asctime_r(struct tm *tim_p ,char *result) -{ - static const char day_name[7][4] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" - }; - static const char mon_name[12][4] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - os_sprintf (result, "%s %s %02d %02d:%02d:%02d %02d\n", - day_name[tim_p->tm_wday], - mon_name[tim_p->tm_mon], - tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min, - tim_p->tm_sec, 1900 + tim_p->tm_year); - return result; -} -char *ICACHE_FLASH_ATTR -sntp_asctime(struct tm *tim_p) -{ - - return sntp_asctime_r (tim_p, reult); -} - -uint32 sntp_get_current_timestamp() -{ - if(realtime_stamp == 0){ - os_printf("please start sntp first !\n"); - return 0; - } else { - return realtime_stamp; - } -} - -char* sntp_get_real_time(time_t t) -{ - return sntp_asctime(sntp_localtime (&t)); -} -/** - * SNTP get time_zone default GMT + 8 - */ -sint8 ICACHE_FLASH_ATTR -sntp_get_timezone(void) -{ - return time_zone; -} -/** - * SNTP set time_zone default GMT + 8 - */ - -bool ICACHE_FLASH_ATTR -sntp_set_timezone(sint8 timezone) -{ - if(timezone >= -11 || timezone <= 13) { - if (sntp_get_timetype()){ - RTC_TZ_SET(time_zone); - } else - time_zone = timezone; - return true; - } else { - return false; - } - -} - -void ICACHE_FLASH_ATTR sntp_set_daylight(int daylight) -{ - if (sntp_get_timetype()){ - RTC_DST_SET(daylight); - } -} - -void ICACHE_FLASH_ATTR -sntp_time_inc(void) -{ - realtime_stamp++; -} -/** - * SNTP processing of received timestamp - */ -static void ICACHE_FLASH_ATTR -sntp_process(u32_t *receive_timestamp) -{ - /* convert SNTP time (1900-based) to unix GMT time (1970-based) - * @todo: if MSB is 1, SNTP time is 2036-based! - */ - time_t t = (ntohl(receive_timestamp[0]) - DIFF_SEC_1900_1970); - if (sntp_get_timetype()){ - u32_t us = 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(&t), us)); - } else{ - /* change system time and/or the update the RTC clock */ - SNTP_SET_SYSTEM_TIME(t); - /* display local time from GMT time */ - t += time_zone * 60 * 60;// format GMT + time_zone TIME ZONE - realtime_stamp = t; - os_timer_disarm(&sntp_timer); - os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL); - os_timer_arm(&sntp_timer, 1000, 1); - } -#if 0 -#if SNTP_CALC_TIME_US - u32_t us = 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(&t), 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 */ - t += time_zone * 60 * 60;// format GMT + time_zone TIME ZONE - realtime_stamp = t; - os_timer_disarm(&sntp_timer); - os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL); - os_timer_arm(&sntp_timer, 1000, 1); -#endif /* SNTP_CALC_TIME_US */ -#endif -} - -/** - * Initialize request struct to be sent to server. - */ -static void ICACHE_FLASH_ATTR -sntp_initialize_request(struct sntp_msg *req) -{ - os_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] = 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] = 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 ICACHE_FLASH_ATTR -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 ICACHE_FLASH_ATTR -sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) -{ - u8_t mode; - u8_t stratum; - u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE]; - err_t err; -//os_printf("sntp_recv\n"); - 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 (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 ((mode == SNTP_MODE_SERVER) || - (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_RECEIVE_TIME); - } - } - } else { - LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode)); - } - } else { - LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len)); - } - } - pbuf_free(p); - if (err == ERR_OK) { - /* Correct response, reset retry timeout */ - SNTP_RESET_RETRY_TIMEOUT(); - - sntp_process(receive_timestamp); - - /* Set up timeout for next request */ - 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 == 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 ICACHE_FLASH_ATTR -sntp_send_request(ip_addr_t *server_addr) -{ - struct pbuf* p; -// os_printf("sntp_send_request\n"); - 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, 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 ICACHE_FLASH_ATTR -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_any(&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; -// os_printf("sntp_server_address ip %d\n",sntp_server_address.addr); - err = (ip_addr_isany(&sntp_server_address)) ? ERR_ARG : ERR_OK; - } - - if (err == ERR_OK) { - LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %u.%u.%u.%u\n", - ip4_addr1(&sntp_server_address), ip4_addr2(&sntp_server_address), ip4_addr3(&sntp_server_address), ip4_addr4(&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); - } -} - -/** - * Initialize this module. - * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC). - */ -void ICACHE_FLASH_ATTR -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_RESET_RETRY_TIMEOUT(); - sntp_pcb = udp_new(); - 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_STARTUP_DELAY - sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL); -#else - sntp_request(NULL); -#endif - } - } -} - -/** - * Stop this module. - */ -void ICACHE_FLASH_ATTR -sntp_stop(void) -{ - if (sntp_pcb != NULL) { - sys_untimeout(sntp_request, NULL); - udp_remove(sntp_pcb); - sntp_pcb = NULL; - } - os_timer_disarm(&sntp_timer); - realtime_stamp = 0; -} - -#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 */ - -/** - * Initialize one of the NTP servers by IP address - * - * @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 ICACHE_FLASH_ATTR -sntp_setserver(u8_t idx, ip_addr_t *server) -{ - if (idx < SNTP_MAX_SERVERS) { - if (server != NULL) { - sntp_servers[idx].addr = (*server); -// os_printf("server ip %d\n",server->addr); - } else { - ip_addr_set_any(&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, ip_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++) { - sntp_setserver(i, &server[i]); - } - for (i = num; i < SNTP_MAX_SERVERS; i++) { - sntp_setserver(i, NULL); - } - } -} -#endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */ - -/** - * Obtain one of the currently configured by IP address (or DHCP) NTP servers - * - * @param numdns 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). - */ -ip_addr_t ICACHE_FLASH_ATTR -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 ICACHE_FLASH_ATTR -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 * ICACHE_FLASH_ATTR -sntp_getservername(u8_t idx) -{ - if (idx < SNTP_MAX_SERVERS) { - return sntp_servers[idx].name; - } - return NULL; -} -#endif /* SNTP_SERVER_DNS */ - -void ICACHE_FLASH_ATTR -sntp_set_update_delay(uint32 ms) -{ - sntp_update_delay = ms > 15000?ms:15000; -} - -void ICACHE_FLASH_ATTR -sntp_set_timetype(bool type) -{ - // sntp_time_flag = type; -} - -bool sntp_get_timetype(void) -{ - return sntp_time_flag; -} - -void ICACHE_FLASH_ATTR -sntp_set_receive_time_size(void) -{ - if (sntp_get_timetype()){ - sntp_receive_time_size = 2; - } else{ - sntp_receive_time_size = 1; - } -} - -#endif /* LWIP_UDP */ diff --git a/tools/sdk/lwip/src/core/stats.c b/tools/sdk/lwip/src/core/stats.c deleted file mode 100644 index 69f97d41f..000000000 --- a/tools/sdk/lwip/src/core/stats.c +++ /dev/null @@ -1,176 +0,0 @@ -/** - * @file - * Statistics module - * - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" - -#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/def.h" -#include "lwip/stats.h" -#include "lwip/mem.h" - -#include - -struct stats_ lwip_stats; - -void stats_init(void) -{ -#ifdef LWIP_DEBUG -#if MEMP_STATS - const char * memp_names[] = { -#define LWIP_MEMPOOL(name,num,size,desc) desc, -#include "lwip/memp_std.h" - }; - int i; - for (i = 0; i < MEMP_MAX; i++) { - lwip_stats.memp[i].name = memp_names[i]; - } -#endif /* MEMP_STATS */ -#if MEM_STATS - lwip_stats.mem.name = "MEM"; -#endif /* MEM_STATS */ -#endif /* LWIP_DEBUG */ -} - -#if LWIP_STATS_DISPLAY -void -stats_display_proto(struct stats_proto *proto, char *name) -{ - LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); - LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit)); - LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv)); - LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw)); - LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop)); - LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr)); - LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr)); - LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr)); - LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr)); - LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr)); - LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr)); - LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err)); - LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit)); -} - -#if IGMP_STATS -void -stats_display_igmp(struct stats_igmp *igmp) -{ - LWIP_PLATFORM_DIAG(("\nIGMP\n\t")); - LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit)); - LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv)); - LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop)); - LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr)); - LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr)); - LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr)); - LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr)); - LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1)); - LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n", igmp->rx_group)); - LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n", igmp->rx_general)); - LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report)); - LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join)); - LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave)); - LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report)); -} -#endif /* IGMP_STATS */ - -#if MEM_STATS || MEMP_STATS -void -stats_display_mem(struct stats_mem *mem, char *name) -{ - LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name)); - LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail)); - LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used)); - LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max)); - LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err)); -} - -#if MEMP_STATS -void -stats_display_memp(struct stats_mem *mem, int index) -{ - char * memp_names[] = { -#define LWIP_MEMPOOL(name,num,size,desc) desc, -#include "lwip/memp_std.h" - }; - if(index < MEMP_MAX) { - stats_display_mem(mem, memp_names[index]); - } -} -#endif /* MEMP_STATS */ -#endif /* MEM_STATS || MEMP_STATS */ - -#if SYS_STATS -void -stats_display_sys(struct stats_sys *sys) -{ - LWIP_PLATFORM_DIAG(("\nSYS\n\t")); - LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used)); - LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max)); - LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err)); - LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used)); - LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max)); - LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err)); - LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used)); - LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max)); - LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err)); -} -#endif /* SYS_STATS */ - -void -stats_display(void) -{ - s16_t i; - - LINK_STATS_DISPLAY(); - ETHARP_STATS_DISPLAY(); - IPFRAG_STATS_DISPLAY(); - IP_STATS_DISPLAY(); - IGMP_STATS_DISPLAY(); - ICMP_STATS_DISPLAY(); - UDP_STATS_DISPLAY(); - TCP_STATS_DISPLAY(); - MEM_STATS_DISPLAY(); - for (i = 0; i < MEMP_MAX; i++) { - MEMP_STATS_DISPLAY(i); - } - SYS_STATS_DISPLAY(); -} -#endif /* LWIP_STATS_DISPLAY */ - -#endif /* LWIP_STATS */ - diff --git a/tools/sdk/lwip/src/core/sys.c b/tools/sdk/lwip/src/core/sys.c deleted file mode 100644 index d3a77deb2..000000000 --- a/tools/sdk/lwip/src/core/sys.c +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file - * lwIP Operating System abstraction - * - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" - -#include "lwip/sys.h" - -/* Most of the functions defined in sys.h must be implemented in the - * architecture-dependent file sys_arch.c */ - -#if !NO_SYS - -/** - * Sleep for some ms. Timeouts are NOT processed while sleeping. - * - * @param ms number of milliseconds to sleep - */ -void -sys_msleep(u32_t ms) -{ - if (ms > 0) { - sys_sem_t delaysem; - err_t err = sys_sem_new(&delaysem, 0); - if (err == ERR_OK) { - sys_arch_sem_wait(&delaysem, ms); - sys_sem_free(&delaysem); - } - } -} - -#endif /* !NO_SYS */ diff --git a/tools/sdk/lwip/src/core/sys_arch.c b/tools/sdk/lwip/src/core/sys_arch.c deleted file mode 100644 index e79042f22..000000000 --- a/tools/sdk/lwip/src/core/sys_arch.c +++ /dev/null @@ -1,13 +0,0 @@ -/* - * copyright (c) 2010 - 2011 espressif system - */ - -#include "c_types.h" -#include "ets_sys.h" -#include "osapi.h" -#include "os_type.h" - -#include "lwip/opt.h" -#include "lwip/sys.h" - -#include "eagle_soc.h" diff --git a/tools/sdk/lwip/src/core/tcp.c b/tools/sdk/lwip/src/core/tcp.c deleted file mode 100644 index a3651c61d..000000000 --- a/tools/sdk/lwip/src/core/tcp.c +++ /dev/null @@ -1,1673 +0,0 @@ -/** - * @file - * Transmission Control Protocol for IP - * - * This file contains common functions for the TCP implementation, such as functinos - * for manipulating the data structures and the TCP timer functions. TCP functions - * related to input and output is found in tcp_in.c and tcp_out.c respectively. - * - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/snmp.h" -#include "lwip/tcp.h" -#include "lwip/tcp_impl.h" -#include "lwip/debug.h" -#include "lwip/stats.h" - -#include - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -#if TCP_DEBUG -const char tcp_state_str_rodata[][12] ICACHE_RODATA_ATTR = { - "CLOSED", - "LISTEN", - "SYN_SENT", - "SYN_RCVD", - "ESTABLISHED", - "FIN_WAIT_1", - "FIN_WAIT_2", - "CLOSE_WAIT", - "CLOSING", - "LAST_ACK", - "TIME_WAIT" -}; - -char tcp_state_str[12]; -#endif - -/* Incremented every coarse grained timer shot (typically every 500 ms). */ -u32_t tcp_ticks; -const u8_t tcp_backoff[13] ICACHE_RODATA_ATTR = - { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; - /* Times per slowtmr hits */ -const u8_t tcp_persist_backoff[7] ICACHE_RODATA_ATTR = { 3, 6, 12, 24, 48, 96, 120 }; - -/* The TCP PCB lists. */ - -/** List of all TCP PCBs bound but not yet (connected || listening) */ -struct tcp_pcb *tcp_bound_pcbs; -/** List of all TCP PCBs in LISTEN state */ -union tcp_listen_pcbs_t tcp_listen_pcbs; -/** List of all TCP PCBs that are in a state in which - * they accept or send data. */ -struct tcp_pcb *tcp_active_pcbs; -/** List of all TCP PCBs in TIME-WAIT state */ -struct tcp_pcb *tcp_tw_pcbs; - -#define NUM_TCP_PCB_LISTS 4 -#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3 -/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ -struct tcp_pcb ** const tcp_pcb_lists[] ICACHE_RODATA_ATTR = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, - &tcp_active_pcbs, &tcp_tw_pcbs}; - -/** Only used for temporary storage. */ -struct tcp_pcb *tcp_tmp_pcb; - -/** Timer counter to handle calling slow-timer from tcp_tmr() */ -static u8_t tcp_timer; -static u16_t tcp_new_port(void);//����µ�tcp���ض˿� - -/** - * Called periodically to dispatch TCP timers. - * - */ -void -tcp_tmr(void) -{ - /* Call tcp_fasttmr() every 250 ms */ - tcp_fasttmr(); - - if (++tcp_timer & 1) { - /* Call tcp_tmr() every 500 ms, i.e., every other timer - tcp_tmr() is called. */ - tcp_slowtmr(); - } -} - -/** - * Closes the TX side of a connection held by the PCB. - * For tcp_close(), a RST is sent if the application didn't receive all data - * (tcp_recved() not called for all data passed to recv callback). - * - * Listening pcbs are freed and may not be referenced any more. - * Connection pcbs are freed if not yet connected and may not be referenced - * any more. If a connection is established (at least SYN received or in - * a closing state), the connection is closed, and put in a closing state. - * The pcb is then automatically freed in tcp_slowtmr(). It is therefore - * unsafe to reference it. - * - * @param pcb the tcp_pcb to close - * @return ERR_OK if connection has been closed - * another err_t if closing failed and pcb is not freed - */ -static err_t -tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) -{ - err_t err; - - if (rst_on_unacked_data && (pcb->state != LISTEN)) { - if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) { - /* Not all data received by application, send RST to tell the remote - side about this. */ - LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED); - - /* don't call tcp_abort here: we must not deallocate the pcb since - that might not be expected when calling tcp_close */ - tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port); - - tcp_pcb_purge(pcb); - - /* TODO: to which state do we move now? */ - - /* move to TIME_WAIT since we close actively */ - TCP_RMV(&tcp_active_pcbs, pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); -#if MEMP_NUM_TCP_PCB_TIME_WAIT - TCP_TW_LIMIT(MEMP_NUM_TCP_PCB_TIME_WAIT); -#endif - return ERR_OK; - } - } - - switch (pcb->state) { - case CLOSED: - /* Closing a pcb in the CLOSED state might seem erroneous, - * however, it is in this state once allocated and as yet unused - * and the user needs some way to free it should the need arise. - * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) - * or for a pcb that has been used and then entered the CLOSED state - * is erroneous, but this should never happen as the pcb has in those cases - * been freed, and so any remaining handles are bogus. */ - /*��CLOSED״̬�¹ر�һ��pcb�ƺ��Ǵ���ģ� - *������ˣ�һ�������״̬�·����˶��һ�û��ʹ��,�û���ҪһЩ�취���ͷ��� - *����һ���Ѿ����رյ�pcb��tcp_close(),(��2��)����һ���Ѿ���ʹ����֮�󣬽���CLOSE״̬�Ǵ���� - *������Щ����±��ͷŵ�pcb�Dz�����ڵ�,��ˣ��κ�ʣ��ľ���Ǽٵ� - */ - err = ERR_OK;//�趨����ֵ - if (pcb->local_port != 0) { - TCP_RMV(&tcp_bound_pcbs, pcb); - } - memp_free(MEMP_TCP_PCB, pcb);//��MEMP_TCP_PCB�ڴ���趨�ͷŵ���pcb��Ӧ�ĵ�Ԫֵ,�ͷ��ڴ� - pcb = NULL; - break; - case LISTEN: - err = ERR_OK; - tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb);//�Ӽ����PCB�б���ɾ���Ӧ��pcb - memp_free(MEMP_TCP_PCB_LISTEN, pcb);//��MEMP_TCP_PCB_LISTEN�ڴ�����趨�ͷŵ�pcb��Ԫֵ ,�ͷ��ڴ� - pcb = NULL; - break; - case SYN_SENT: - err = ERR_OK; - tcp_pcb_remove(&tcp_active_pcbs, pcb); - memp_free(MEMP_TCP_PCB, pcb); - pcb = NULL; - snmp_inc_tcpattemptfails(); - break; - case SYN_RCVD: - err = tcp_send_fin(pcb);//���������ر�FIN���ֱ��� - if (err == ERR_OK) { - snmp_inc_tcpattemptfails(); - pcb->state = FIN_WAIT_1;//ת��FIN_WAIT_1״̬ - } - break; - case ESTABLISHED: - err = tcp_send_fin(pcb); - if (err == ERR_OK) { - snmp_inc_tcpestabresets(); - pcb->state = FIN_WAIT_1; - } - break; - case CLOSE_WAIT: - err = tcp_send_fin(pcb); - if (err == ERR_OK) { - snmp_inc_tcpestabresets(); - pcb->state = LAST_ACK;//����LAST_ACK�ȴ�ACK��ʱ - } - break; - default: - /* Has already been closed, do nothing. */ - err = ERR_OK; - pcb = NULL; - break; - } - - if (pcb != NULL && err == ERR_OK) { - /* To ensure all data has been sent when tcp_close returns, we have - to make sure tcp_output doesn't fail. - Since we don't really have to ensure all data has been sent when tcp_close - returns (unsent data is sent from tcp timer functions, also), we don't care - for the return value of tcp_output for now. */ - /* @todo: When implementing SO_LINGER, this must be changed somehow: - If SOF_LINGER is set, the data should be sent and acked before close returns. - This can only be valid for sequential APIs, not for the raw API. */ - tcp_output(pcb);//���ú����Ϳ��ƿ������ʣ��ı��ģ�����FIN���ֱ��Ķ� - } - return err; -} - -/** - * Closes the connection held by the PCB. - * - * Listening pcbs are freed and may not be referenced any more. - * Connection pcbs are freed if not yet connected and may not be referenced - * any more. If a connection is established (at least SYN received or in - * a closing state), the connection is closed, and put in a closing state. - * The pcb is then automatically freed in tcp_slowtmr(). It is therefore - * unsafe to reference it (unless an error is returned). - * - * @param pcb the tcp_pcb to close - * @return ERR_OK if connection has been closed - * another err_t if closing failed and pcb is not freed - */ - /* - *ͨ��PCB�ر��������� - *�����е�pcbӦ�ñ��ͷŵģ�Ҳ����ԶҲ���ᱻʹ���� - *���û�����ӻ�����Ҳû�б�����,���ӵ�pcbӦ�ñ��ͷŵ� - *���һ�����ӱ�����(����SYN�Ѿ������ջ�����һ���ر��е�״̬) - *���ӱ��ر��ˣ�����������һ�����ڹرյ�״̬ - *pcb�Զ���tcp_slowtmr()�ͷ�,�����������Dz���ȫ�� - */ -err_t -tcp_close(struct tcp_pcb *pcb) -{ -#if TCP_DEBUG //TCP debug��Ϣ����ӡpcb��״̬ - LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); - tcp_debug_print_state(pcb->state); -#endif /* TCP_DEBUG */ - - if (pcb->state != LISTEN) { - /* Set a flag not to receive any more data... */ - pcb->flags |= TF_RXCLOSED; - } - /* ... and close */ - return tcp_close_shutdown(pcb, 1); -} - -/** - * Causes all or part of a full-duplex connection of this PCB to be shut down. - * This doesn't deallocate the PCB! - * - * @param pcb PCB to shutdown - * @param shut_rx shut down receive side if this is != 0 - * @param shut_tx shut down send side if this is != 0 - * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down) - * another err_t on error. - */ -err_t -tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) -{ - if (pcb->state == LISTEN) { - return ERR_CONN; - } - if (shut_rx) { - /* shut down the receive side: free buffered data... */ - if (pcb->refused_data != NULL) { - pbuf_free(pcb->refused_data); - pcb->refused_data = NULL; - } - /* ... and set a flag not to receive any more data */ - pcb->flags |= TF_RXCLOSED; - } - if (shut_tx) { - /* This can't happen twice since if it succeeds, the pcb's state is changed. - Only close in these states as the others directly deallocate the PCB */ - switch (pcb->state) { - case SYN_RCVD: - case ESTABLISHED: - case CLOSE_WAIT: - return tcp_close_shutdown(pcb, 0); - default: - /* don't shut down other states */ - break; - } - } - /* @todo: return another err_t if not in correct state or already shut? */ - return ERR_OK; -} - -/** - * Abandons a connection and optionally sends a RST to the remote - * host. Deletes the local protocol control block. This is done when - * a connection is killed because of shortage of memory. - * - * @param pcb the tcp_pcb to abort - * @param reset boolean to indicate whether a reset should be sent - */ -void -tcp_abandon(struct tcp_pcb *pcb, int reset) -{ - u32_t seqno, ackno; - u16_t remote_port, local_port; - ip_addr_t remote_ip, local_ip; -#if LWIP_CALLBACK_API - tcp_err_fn errf; -#endif /* LWIP_CALLBACK_API */ - void *errf_arg; - - /* pcb->state LISTEN not allowed here */ - LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs", - pcb->state != LISTEN); - /* Figure out on which TCP PCB list we are, and remove us. If we - are in an active state, call the receive function associated with - the PCB with a NULL argument, and send an RST to the remote end. */ - if (pcb->state == TIME_WAIT) { - tcp_pcb_remove(&tcp_tw_pcbs, pcb); - memp_free(MEMP_TCP_PCB, pcb); - } else { - seqno = pcb->snd_nxt; - ackno = pcb->rcv_nxt; - ip_addr_copy(local_ip, pcb->local_ip); - ip_addr_copy(remote_ip, pcb->remote_ip); - local_port = pcb->local_port; - remote_port = pcb->remote_port; -#if LWIP_CALLBACK_API - errf = pcb->errf; -#endif /* LWIP_CALLBACK_API */ - errf_arg = pcb->callback_arg; - tcp_pcb_remove(&tcp_active_pcbs, pcb); - if (pcb->unacked != NULL) { - tcp_segs_free(pcb->unacked); - } - if (pcb->unsent != NULL) { - tcp_segs_free(pcb->unsent); - } -#if TCP_QUEUE_OOSEQ - if (pcb->ooseq != NULL) { - tcp_segs_free(pcb->ooseq); - } -#endif /* TCP_QUEUE_OOSEQ */ - if (reset) { - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); - tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port); - } - TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); - memp_free(MEMP_TCP_PCB, pcb); - } -} - -/** - * Aborts the connection by sending a RST (reset) segment to the remote - * host. The pcb is deallocated. This function never fails. - * - * ATTENTION: When calling this from one of the TCP callbacks, make - * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise - * or you will risk accessing deallocated memory or memory leaks! - * - * @param pcb the tcp pcb to abort - */ -void -tcp_abort(struct tcp_pcb *pcb) -{ - tcp_abandon(pcb, 1); -} - -/** - * Binds the connection to a local portnumber and IP address. If the - * IP address is not given (i.e., ipaddr == NULL), the IP address of - * the outgoing network interface is used instead. - * - * @param pcb the tcp_pcb to bind (no check is done whether this pcb is - * already bound!) - * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind - * to any local address - * @param port the local port to bind to - * @return ERR_USE if the port is already in use - * ERR_OK if bound - */ -err_t -tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) -{ - int i; - int max_pcb_list = NUM_TCP_PCB_LISTS; - struct tcp_pcb *cpcb; - - LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); - -#if SO_REUSE - /* Unless the REUSEADDR flag is set, - we have to check the pcbs in TIME-WAIT state, also. - We do not dump TIME_WAIT pcb's; they can still be matched by incoming - packets using both local and remote IP addresses and ports to distinguish. - */ - if ((pcb->so_options & SOF_REUSEADDR) != 0) { - max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT; - } -#endif /* SO_REUSE */ - - if (port == 0) { - port = tcp_new_port(); - } - - /* Check if the address already is in use (on all lists) */ - for (i = 0; i < max_pcb_list; i++) { - for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { - if (cpcb->local_port == port) { -#if SO_REUSE - /* Omit checking for the same port if both pcbs have REUSEADDR set. - For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in - tcp_connect. */ - if (((pcb->so_options & SOF_REUSEADDR) == 0) || - ((cpcb->so_options & SOF_REUSEADDR) == 0)) -#endif /* SO_REUSE */ - { - if (ip_addr_isany(&(cpcb->local_ip)) || - ip_addr_isany(ipaddr) || - ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { - //os_printf("Address in use\n"); - return ERR_USE; - } - } - } - } - } - - if (!ip_addr_isany(ipaddr)) { - pcb->local_ip = *ipaddr; - } - pcb->local_port = port; - TCP_REG(&tcp_bound_pcbs, pcb); - LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port)); - return ERR_OK; -} -#if LWIP_CALLBACK_API -/** - * Default accept callback if no accept callback is specified by the user. - */ -static err_t -tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) -{ - LWIP_UNUSED_ARG(arg); - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(err); - - return ERR_ABRT; -} -#endif /* LWIP_CALLBACK_API */ - -/** - * Set the state of the connection to be LISTEN, which means that it - * is able to accept incoming connections. The protocol control block - * is reallocated in order to consume less memory. Setting the - * connection to LISTEN is an irreversible process. - *��ij���󶨵Ŀ��ƿ���Ϊ����״̬ - * @param pcb the original tcp_pcb �����Ŀ��ƿ���� - * @param backlog the incoming connections queue limit - * @return tcp_pcb used for listening, consumes less memory.ָ������״̬�Ŀ��ƿ� - * - * @note The original tcp_pcb is freed. This function therefore has to be - * called like this: - * tpcb = tcp_listen(tpcb); - */ -struct tcp_pcb * -tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) -{ - struct tcp_pcb_listen *lpcb; - - LWIP_UNUSED_ARG(backlog); - LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL); - - /* already listening? */ - if (pcb->state == LISTEN) { - return pcb; - } -#if SO_REUSE - if ((pcb->so_options & SOF_REUSEADDR) != 0) { - /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage - is declared (listen-/connection-pcb), we have to make sure now that - this port is only used once for every local IP. */ - for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { - if (lpcb->local_port == pcb->local_port) { - if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { - /* this address/port is already used */ - return NULL; - } - } - } - } -#endif /* SO_REUSE */ - lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN);//�����ڴ�ؿռ� - if (lpcb == NULL) { - return NULL; - } - lpcb->callback_arg = pcb->callback_arg; - lpcb->local_port = pcb->local_port; - lpcb->state = LISTEN; - lpcb->prio = pcb->prio; - lpcb->so_options = pcb->so_options; - lpcb->so_options |= SOF_ACCEPTCONN; - lpcb->ttl = pcb->ttl; - lpcb->tos = pcb->tos; - ip_addr_copy(lpcb->local_ip, pcb->local_ip); - if (pcb->local_port != 0) { - TCP_RMV(&tcp_bound_pcbs, pcb); - } - memp_free(MEMP_TCP_PCB, pcb); -#if LWIP_CALLBACK_API - lpcb->accept = tcp_accept_null;//���ܿͻ������ӵ�Ĭ�ϻص����� -#endif /* LWIP_CALLBACK_API */ -#if TCP_LISTEN_BACKLOG - lpcb->accepts_pending = 0; - lpcb->backlog = (backlog ? backlog : 1); -#endif /* TCP_LISTEN_BACKLOG */ - TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb);//���ƿ����tcp_listen_pcbs�����ײ� - return (struct tcp_pcb *)lpcb; -} - -/** - * Update the state that tracks the available window space to advertise. - * - * Returns how much extra window would be advertised if we sent an - * update now. - */ -u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) -{ - u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd; - - if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) { - /* we can advertise more window */ - pcb->rcv_ann_wnd = pcb->rcv_wnd; - return new_right_edge - pcb->rcv_ann_right_edge; - } else { - if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) { - /* Can happen due to other end sending out of advertised window, - * but within actual available (but not yet advertised) window */ - pcb->rcv_ann_wnd = 0; - } else { - /* keep the right edge of window constant */ - u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; - LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff); - pcb->rcv_ann_wnd = (u16_t)new_rcv_ann_wnd; - } - return 0; - } -} - -/** - * This function should be called by the application when it has - * processed the data. The purpose is to advertise a larger window - * when the data has been processed. - *Ӧ�ó�����ݴ�����Ϻ�֪ͨ�ں˸��½��մ��� - * @param pcb the tcp_pcb for which data is read - * @param len the amount of bytes that have been read by the application - */ -void -tcp_recved(struct tcp_pcb *pcb, u16_t len) -{ - int wnd_inflation; - - LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n", - len <= 0xffff - pcb->rcv_wnd ); - - pcb->rcv_wnd += len; - if (pcb->rcv_wnd > TCP_WND) { - pcb->rcv_wnd = TCP_WND; - } - - wnd_inflation = tcp_update_rcv_ann_wnd(pcb); - - /* If the change in the right edge of window is significant (default - * watermark is TCP_WND/4), then send an explicit update now. - * Otherwise wait for a packet to be sent in the normal course of - * events (or more window to be available later) */ - if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) { - tcp_ack_now(pcb); - tcp_output(pcb); - } - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n", - len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd)); -} - -/** - * A nastly hack featuring 'goto' statements that allocates a - * new TCP local port. - * - * @return a new (free) local TCP port number - */ -static u16_t -tcp_new_port(void) -{ - int i; - struct tcp_pcb *pcb; -#ifndef TCP_LOCAL_PORT_RANGE_START -#define TCP_LOCAL_PORT_RANGE_START 1024 -#define TCP_LOCAL_PORT_RANGE_END 0x7fff -#endif - static u16_t port = TCP_LOCAL_PORT_RANGE_START; - - again: -// if (++port >= TCP_LOCAL_PORT_RANGE_END) { -// port = TCP_LOCAL_PORT_RANGE_START; -// } - port = os_random(); - port %= TCP_LOCAL_PORT_RANGE_END; - if (port < TCP_LOCAL_PORT_RANGE_START) - port += TCP_LOCAL_PORT_RANGE_START; - /* Check all PCB lists. */ - for (i = 0; i < NUM_TCP_PCB_LISTS; i++) { - for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) { - if (pcb->local_port == port) { - goto again; - } - } - } - return port; -} - -/** - * Connects to another host. The function given as the "connected" - * argument will be called when the connection has been established. - *�����������һ��SYN���ֱ��� - * @param pcb the tcp_pcb used to establish the connection �����Ŀ��ƿ���� - * @param ipaddr the remote ip address to connect to ������IP��ַ - * @param port the remote tcp port to connect to �������˿ں� - * @param connected callback function to call when connected (or on error) - * @return ERR_VAL if invalid arguments are given - * ERR_OK if connect request has been sent - * other err_t values if connect request couldn't be sent - */ -err_t -tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, - tcp_connected_fn connected) -{ - err_t ret; - u32_t iss; - u16_t old_local_port; - - LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); - if (ipaddr != NULL) { - pcb->remote_ip = *ipaddr;//������IP��ַ��Ч�������Ӽ�¼�м�¼��IP��ַ�����ò·µ»Ø´ï¿½ï¿½ï¿½ - } else { - return ERR_VAL; - } - pcb->remote_port = port;//��¼�������˿�(Ŀ�Ķ˿�) - - /* check if we have a route to the remote host */ - if (ip_addr_isany(&(pcb->local_ip))) { - /* no local IP address set, yet. */ - struct netif *netif = ip_route(&(pcb->remote_ip)); - if (netif == NULL) { - /* Don't even try to send a SYN packet if we have no route - since that will fail. */ - return ERR_RTE; - } - /* Use the netif's IP address as local address. */ - ip_addr_copy(pcb->local_ip, netif->ip_addr); - } - - old_local_port = pcb->local_port; - if (pcb->local_port == 0) { - pcb->local_port = tcp_new_port(); - - } -#if SO_REUSE - if ((pcb->so_options & SOF_REUSEADDR) != 0) { - /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure - now that the 5-tuple is unique. */ - struct tcp_pcb *cpcb; - int i; - /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */ - for (i = 2; i < NUM_TCP_PCB_LISTS; i++) { - for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { - if ((cpcb->local_port == pcb->local_port) && - (cpcb->remote_port == port) && - ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) && - ip_addr_cmp(&cpcb->remote_ip, ipaddr)) { - /* linux returns EISCONN here, but ERR_USE should be OK for us */ - return ERR_USE; - } - } - } - } -#endif /* SO_REUSE */ - iss = tcp_next_iss();//��ʼ����� - pcb->rcv_nxt = 0;//���÷��ʹ��ڵĸ����ֶ� - pcb->snd_nxt = iss; - pcb->lastack = iss - 1; - pcb->snd_lbb = iss - 1; - pcb->rcv_wnd = TCP_WND;//����Ĭ�Ͻ��մ��ڸ����ֶ�ֵ - pcb->rcv_ann_wnd = TCP_WND; - pcb->rcv_ann_right_edge = pcb->rcv_nxt; - pcb->snd_wnd = TCP_WND; - /* As initial send MSS, we use TCP_MSS but limit it to 536. - The send MSS is updated when an MSS option is received. */ - pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;//��ʼ������Ķδ�С -#if TCP_CALCULATE_EFF_SEND_MSS - pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr); -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - pcb->cwnd = 1;//��ʼ������� - pcb->ssthresh = pcb->mss * 10; -#if LWIP_CALLBACK_API - pcb->connected = connected;//ע��connected�ص����� -#else /* LWIP_CALLBACK_API */ - LWIP_UNUSED_ARG(connected); -#endif /* LWIP_CALLBACK_API */ - - /* Send a SYN together with the MSS option. */ - ret = tcp_enqueue_flags(pcb, TCP_SYN); - if (ret == ERR_OK) { - /* SYN segment was enqueued, changed the pcbs state now ���ƿ�����ΪSYN_SENT ״̬*/ - pcb->state = SYN_SENT; - if (old_local_port != 0) { - TCP_RMV(&tcp_bound_pcbs, pcb); - } - TCP_REG(&tcp_active_pcbs, pcb); - snmp_inc_tcpactiveopens(); - - tcp_output(pcb);//�����ƿ������ӵı��ķ��ͳ�ȥ - } - return ret; -} - -/** - * Called every 500 ms and implements the retransmission timer and the timer that - * removes PCBs that have been in TIME-WAIT for enough time. It also increments - * various timers such as the inactivity timer in each PCB. - * - * Automatically called from tcp_tmr(). - */ -void -tcp_slowtmr(void) -{ - struct tcp_pcb *pcb, *prev; - u16_t eff_wnd; - u8_t pcb_remove; /* flag if a PCB should be removed */ - u8_t pcb_reset; /* flag if a RST should be sent when removing */ - err_t err; - - err = ERR_OK; - - ++tcp_ticks; - - /* Steps through all of the active PCBs. */ - prev = NULL; - pcb = tcp_active_pcbs; - if (pcb == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n")); - } - while (pcb != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n")); - LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED); - LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN); - LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT); - - pcb_remove = 0; - pcb_reset = 0; - - if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) { - ++pcb_remove; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); - } - else if (pcb->nrtx == TCP_MAXRTX) { - ++pcb_remove; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); - } else { - if (pcb->persist_backoff > 0) { - /* If snd_wnd is zero, use persist timer to send 1 byte probes - * instead of using the standard retransmission mechanism. */ - pcb->persist_cnt++; - if (pcb->persist_cnt >= system_get_data_of_array_8(tcp_persist_backoff, pcb->persist_backoff-1)) { - pcb->persist_cnt = 0; - if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) { - pcb->persist_backoff++; - } - tcp_zero_window_probe(pcb); - } - } else { - /* Increase the retransmission timer if it is running */ - if(pcb->rtime >= 0) - ++pcb->rtime; - - if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { - /* Time for a retransmission. */ - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F - " pcb->rto %"S16_F"\n", - pcb->rtime, pcb->rto)); - - /* Double retransmission time-out unless we are trying to - * connect to somebody (i.e., we are in SYN_SENT). */ - if (pcb->state != SYN_SENT) { - pcb->rto = ((pcb->sa >> 3) + pcb->sv) << system_get_data_of_array_8(tcp_backoff, pcb->nrtx); -// if (pcb->rto >= TCP_MAXRTO) -// pcb->rto >>= 1; - } - - /* Reset the retransmission timer. */ - pcb->rtime = 0; - - /* Reduce congestion window and ssthresh. */ - eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); - pcb->ssthresh = eff_wnd >> 1; - if (pcb->ssthresh < (pcb->mss << 1)) { - pcb->ssthresh = (pcb->mss << 1); - } - pcb->cwnd = pcb->mss; - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F - " ssthresh %"U16_F"\n", - pcb->cwnd, pcb->ssthresh)); - - /* The following needs to be called AFTER cwnd is set to one - mss - STJ */ - tcp_rexmit_rto(pcb); - } - } - } - /* Check if this PCB has stayed too long in FIN-WAIT-2 */ - if (pcb->state == FIN_WAIT_2) { - if ((u32_t)(tcp_ticks - pcb->tmr) > - TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { - ++pcb_remove; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); - } - } - - /* Check if KEEPALIVE should be sent */ - if((pcb->so_options & SOF_KEEPALIVE) && - ((pcb->state == ESTABLISHED) || - (pcb->state == CLOSE_WAIT))) { -#if LWIP_TCP_KEEPALIVE - if((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl)) - / TCP_SLOW_INTERVAL) -#else - if((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL) -#endif /* LWIP_TCP_KEEPALIVE */ - { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n", - ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), - ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); - - ++pcb_remove; - ++pcb_reset; - } -#if LWIP_TCP_KEEPALIVE - else if((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl) - / TCP_SLOW_INTERVAL) -#else - else if((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT) - / TCP_SLOW_INTERVAL) -#endif /* LWIP_TCP_KEEPALIVE */ - { - tcp_keepalive(pcb); - pcb->keep_cnt_sent++; - } - } - - /* If this PCB has queued out of sequence data, but has been - inactive for too long, will drop the data (it will eventually - be retransmitted). */ -#if TCP_QUEUE_OOSEQ - if (pcb->ooseq != NULL && - (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) { - tcp_segs_free(pcb->ooseq); - pcb->ooseq = NULL; - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); - } -#endif /* TCP_QUEUE_OOSEQ */ - - /* Check if this PCB has stayed too long in SYN-RCVD */ - if (pcb->state == SYN_RCVD) { - if ((u32_t)(tcp_ticks - pcb->tmr) > - TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { - ++pcb_remove; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); - } - } - - /* Check if this PCB has stayed too long in LAST-ACK */ - if (pcb->state == LAST_ACK) { - if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { - ++pcb_remove; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); - } - } - - /* If the PCB should be removed, do it. */ - if (pcb_remove) { - struct tcp_pcb *pcb2; - tcp_pcb_purge(pcb); - /* Remove PCB from tcp_active_pcbs list. */ - if (prev != NULL) { - LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); - prev->next = pcb->next; - } else { - /* This PCB was the first. */ - LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); - tcp_active_pcbs = pcb->next; - } - - if (pcb_reset) { - tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port); - } - - TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT); - pcb2 = pcb; - pcb = pcb->next; - memp_free(MEMP_TCP_PCB, pcb2); - } else { - /* get the 'next' element now and work with 'prev' below (in case of abort) */ - prev = pcb; - pcb = pcb->next; - - /* We check if we should poll the connection. */ - ++prev->polltmr; - if (prev->polltmr >= prev->pollinterval) { - prev->polltmr = 0; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); - TCP_EVENT_POLL(prev, err); - /* if err == ERR_ABRT, 'prev' is already deallocated */ - if (err == ERR_OK) { - tcp_output(prev); - } - } - } - } - - - /* Steps through all of the TIME-WAIT PCBs. */ - prev = NULL; - pcb = tcp_tw_pcbs; - while (pcb != NULL) { - LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); - pcb_remove = 0; - - /* Check if this PCB has stayed long enough in TIME-WAIT */ - if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { - ++pcb_remove; - } - - - - /* If the PCB should be removed, do it. */ - if (pcb_remove) { - struct tcp_pcb *pcb2; - tcp_pcb_purge(pcb); - /* Remove PCB from tcp_tw_pcbs list. */ - if (prev != NULL) { - LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); - prev->next = pcb->next; - } else { - /* This PCB was the first. */ - LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); - tcp_tw_pcbs = pcb->next; - } - pcb2 = pcb; - pcb = pcb->next; - memp_free(MEMP_TCP_PCB, pcb2); - } else { - prev = pcb; - pcb = pcb->next; - } - } -} - -/** - * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously - * "refused" by upper layer (application) and sends delayed ACKs. - * - * Automatically called from tcp_tmr(). - */ -void -tcp_fasttmr(void) -{ - struct tcp_pcb *pcb = tcp_active_pcbs; - - while(pcb != NULL) { - struct tcp_pcb *next = pcb->next; - /* If there is data which was previously "refused" by upper layer */ - if (pcb->refused_data != NULL) { - /* Notify again application with data previously received. */ - err_t err; - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n")); - TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); - if (err == ERR_OK) { - pcb->refused_data = NULL; - } else if (err == ERR_ABRT) { - /* if err == ERR_ABRT, 'pcb' is already deallocated */ - pcb = NULL; - } - } - - /* send delayed ACKs */ - if (pcb && (pcb->flags & TF_ACK_DELAY)) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); - tcp_ack_now(pcb); - tcp_output(pcb); - pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); - } - - pcb = next; - } -} - -/** - * Deallocates a list of TCP segments (tcp_seg structures). - * - * @param seg tcp_seg list of TCP segments to free - */ -void -tcp_segs_free(struct tcp_seg *seg) -{ - while (seg != NULL) { - struct tcp_seg *next = seg->next; - tcp_seg_free(seg); - seg = next; - } -} - -/** - * Frees a TCP segment (tcp_seg structure). - * - * @param seg single tcp_seg to free - */ -void -tcp_seg_free(struct tcp_seg *seg) -{ - if (seg != NULL) { - if (seg->p != NULL) { - pbuf_free(seg->p); -#if TCP_DEBUG - seg->p = NULL; -#endif /* TCP_DEBUG */ - } - memp_free(MEMP_TCP_SEG, seg); - } -} - -/** - * Sets the priority of a connection. - * - * @param pcb the tcp_pcb to manipulate - * @param prio new priority - */ -void -tcp_setprio(struct tcp_pcb *pcb, u8_t prio) -{ - pcb->prio = prio; -} - -#if TCP_QUEUE_OOSEQ -/** - * Returns a copy of the given TCP segment. - * The pbuf and data are not copied, only the pointers - * - * @param seg the old tcp_seg - * @return a copy of seg - */ -struct tcp_seg * -tcp_seg_copy(struct tcp_seg *seg) -{ - struct tcp_seg *cseg; - - cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG); - if (cseg == NULL) { - return NULL; - } - SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); - pbuf_ref(cseg->p); - return cseg; -} -#endif /* TCP_QUEUE_OOSEQ */ - -#if LWIP_CALLBACK_API -/** - * Default receive callback that is called if the user didn't register - * a recv callback for the pcb. - */ -err_t -tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) -{ - LWIP_UNUSED_ARG(arg); - if (p != NULL) { - tcp_recved(pcb, p->tot_len); - pbuf_free(p); - } else if (err == ERR_OK) { - return tcp_close(pcb); - } - return ERR_OK; -} -#endif /* LWIP_CALLBACK_API */ - -/** - * Kills the oldest active connection that has lower priority than prio. - * - * @param prio minimum priority - */ -static void ICACHE_FLASH_ATTR -tcp_kill_prio(u8_t prio) -{ - struct tcp_pcb *pcb, *inactive; - u32_t inactivity; - u8_t mprio; - - - mprio = TCP_PRIO_MAX; - - /* We kill the oldest active connection that has lower priority than prio. */ - inactivity = 0; - inactive = NULL; - for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - if (pcb->prio <= prio && - pcb->prio <= mprio && - (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { - inactivity = tcp_ticks - pcb->tmr; - inactive = pcb; - mprio = pcb->prio; - } - } - if (inactive != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", - (void *)inactive, inactivity)); - tcp_abort(inactive); - } -} - -/** - * Kills the oldest connection that is in TIME_WAIT state. - * Called from tcp_alloc() if no more connections are available. - */ -static void ICACHE_FLASH_ATTR -tcp_kill_timewait(void) -{ - struct tcp_pcb *pcb, *inactive; - u32_t inactivity; - - inactivity = 0; - inactive = NULL; - /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ - for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { - if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { - inactivity = tcp_ticks - pcb->tmr; - inactive = pcb; - } - } - if (inactive != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", - (void *)inactive, inactivity)); - tcp_abort(inactive); - } -} - -/** - * Allocate a new tcp_pcb structure. - *����һ��TCP���ƿ�ṹ������ʼ������ֶ� - * @param prio priority for the new pcb �¿��ƿ�����ȼ� - * @return a new tcp_pcb that initially is in state CLOSED ָ���¿��ƿ��ָ�� - */ -struct tcp_pcb * -tcp_alloc(u8_t prio) -{ - struct tcp_pcb *pcb; - u32_t iss; - - pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);//�����ڴ�ؿռ� - if (pcb == NULL) { - //os_printf("tcp_pcb memory is fail\n"); - /* Try killing oldest connection in TIME-WAIT. */ - LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); - tcp_kill_timewait(); - /* Try to allocate a tcp_pcb again. */ - pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); - if (pcb == NULL) { - /* Try killing active connections with lower priority than the new one. */ - LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio)); - tcp_kill_prio(prio); - /* Try to allocate a tcp_pcb again. */ - pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); - if (pcb != NULL) { - /* adjust err stats: memp_malloc failed twice before */ - MEMP_STATS_DEC(err, MEMP_TCP_PCB); - } - } - if (pcb != NULL) { - /* adjust err stats: timewait PCB was freed above */ - MEMP_STATS_DEC(err, MEMP_TCP_PCB); - } - } - if (pcb != NULL) { - os_memset(pcb, 0, sizeof(struct tcp_pcb)); //��0 - pcb->prio = prio; //�������ȼ� - pcb->snd_buf = TCP_SND_BUF; //��ʹ�õķ��ͻ������С - pcb->snd_queuelen = 0; //��������ռ�õ�pbuf���� - pcb->rcv_wnd = TCP_WND; //���մ��� - pcb->rcv_ann_wnd = TCP_WND; //ͨ����մ��� - pcb->tos = 0; //�������� - pcb->ttl = TCP_TTL; //ttl�ֶ� - /* As initial send MSS, we use TCP_MSS but limit it to 536. - The send MSS is updated when an MSS option is received. */ - pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; //��ʼ������Ķ� - pcb->rto = 1000 / TCP_SLOW_INTERVAL; //��ʼ����ʱʱ�� - pcb->sa = 0; //��ʼ����RTT��صIJ��� - pcb->sv = 1000 / TCP_SLOW_INTERVAL; - pcb->rtime = -1; - pcb->cwnd = 1; //��ʼ������� - iss = tcp_next_iss(); //��ó�ʼ���к� - pcb->snd_wl2 = iss; //��ʼ�����ʹ��ڸ����ֶ� - pcb->snd_nxt = iss; - pcb->lastack = iss; - pcb->snd_lbb = iss; - pcb->tmr = tcp_ticks; //��¼���ƿ鴴��ϵͳʱ�� - - pcb->polltmr = 0; //����������¼���ʱ�� - -#if LWIP_CALLBACK_API - pcb->recv = tcp_recv_null; //ע�������ݵ�Ĭ���ϲ㺯�� -#endif /* LWIP_CALLBACK_API */ - - /* Init KEEPALIVE timer */ - pcb->keep_idle = TCP_KEEPIDLE_DEFAULT; - -#if LWIP_TCP_KEEPALIVE - pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT; - pcb->keep_cnt = TCP_KEEPCNT_DEFAULT; -#endif /* LWIP_TCP_KEEPALIVE */ - - pcb->keep_cnt_sent = 0; //���ķ��ʹ��� - } - return pcb; -} - -/** - * Creates a new TCP protocol control block but doesn't place it on - * any of the TCP PCB lists. - * The pcb is not put on any list until binding using tcp_bind(). - * - * @internal: Maybe there should be a idle TCP PCB list where these - * PCBs are put on. Port reservation using tcp_bind() is implemented but - * allocated pcbs that are not bound can't be killed automatically if wanting - * to allocate a pcb with higher prio (@see tcp_kill_prio()) - * - * @return a new tcp_pcb that initially is in state CLOSED - */ -struct tcp_pcb * -tcp_new(void) -{ - return tcp_alloc(TCP_PRIO_NORMAL); -} - -/** - * Used to specify the argument that should be passed callback - * functions. - *����ƿ��callback_arg�ֶ�ע���û���ݣ���tcp_recv�Ⱥ���ص�ʱ�� -* ���ֶν���Ϊ����ݸ�������� - * @param pcb tcp_pcb to set the callback argument - * @param arg void pointer argument to pass to callback functions - */ -void -tcp_arg(struct tcp_pcb *pcb, void *arg) -{ - pcb->callback_arg = arg; -} -#if LWIP_CALLBACK_API - -/** - * Used to specify the function that should be called when a TCP - * connection receives data. - *����ƿ��recv�ֶ�ע�ắ���յ����ʱ�ص� - * @param pcb tcp_pcb to set the recv callback - * @param recv callback function to call for this pcb when data is received - */ -void -tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv) -{ - pcb->recv = recv; -} - -/** - * Used to specify the function that should be called when TCP data - * has been successfully delivered to the remote host. - *����ƿ�send �ֶ�ע�ắ����ݷ��ͳɹ���ص� - * @param pcb tcp_pcb to set the sent callback - * @param sent callback function to call for this pcb when data is successfully sent - */ -void -tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent) -{ - pcb->sent = sent; -} - -/** - * Used to specify the function that should be called when a fatal error - * has occured on the connection. - *����ƿ�err �ֶ�ע�ắ�����������ص� - * @param pcb tcp_pcb to set the err callback - * @param err callback function to call for this pcb when a fatal error - * has occured on the connection - */ -void -tcp_err(struct tcp_pcb *pcb, tcp_err_fn err) -{ - pcb->errf = err; -} - -/** - * Used for specifying the function that should be called when a - * LISTENing connection has been connected to another host. - *����ƿ��accept�ֶ�ע�ắ����������ʱ�ص� - * @param pcb tcp_pcb to set the accept callback - * @param accept callback function to call for this pcb when LISTENing - * connection has been connected to another host - */ -void -tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept) -{ - pcb->accept = accept; -} -#endif /* LWIP_CALLBACK_API */ - - -/** - * Used to specify the function that should be called periodically - * from TCP. The interval is specified in terms of the TCP coarse - * timer interval, which is called twice a second. - *����ƿ��POLL�ֶ�ע�ắ��ú��������Ա����� - */ -void -tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) -{ -#if LWIP_CALLBACK_API - pcb->poll = poll; -#else /* LWIP_CALLBACK_API */ - LWIP_UNUSED_ARG(poll); -#endif /* LWIP_CALLBACK_API */ - pcb->pollinterval = interval; -} - -/** - * Purges a TCP PCB. Removes any buffered data and frees the buffer memory - * (pcb->ooseq, pcb->unsent and pcb->unacked are freed). - * - * @param pcb tcp_pcb to purge. The pcb itself is not deallocated! - */ -void -tcp_pcb_purge(struct tcp_pcb *pcb) -{ - if (pcb->state != CLOSED && - pcb->state != TIME_WAIT && - pcb->state != LISTEN) { - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); - -#if TCP_LISTEN_BACKLOG - if (pcb->state == SYN_RCVD) { - /* Need to find the corresponding listen_pcb and decrease its accepts_pending */ - struct tcp_pcb_listen *lpcb; - LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL", - tcp_listen_pcbs.listen_pcbs != NULL); - for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { - if ((lpcb->local_port == pcb->local_port) && - (ip_addr_isany(&lpcb->local_ip) || - ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) { - /* port and address of the listen pcb match the timed-out pcb */ - LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending", - lpcb->accepts_pending > 0); - lpcb->accepts_pending--; - break; - } - } - } -#endif /* TCP_LISTEN_BACKLOG */ - - - if (pcb->refused_data != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n")); - pbuf_free(pcb->refused_data); - pcb->refused_data = NULL; - } - if (pcb->unsent != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); - } - if (pcb->unacked != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); - } -#if TCP_QUEUE_OOSEQ - if (pcb->ooseq != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); - } - tcp_segs_free(pcb->ooseq); - pcb->ooseq = NULL; -#endif /* TCP_QUEUE_OOSEQ */ - - /* Stop the retransmission timer as it will expect data on unacked - queue if it fires */ - pcb->rtime = -1; - - tcp_segs_free(pcb->unsent); - tcp_segs_free(pcb->unacked); - pcb->unacked = pcb->unsent = NULL; -#if TCP_OVERSIZE - pcb->unsent_oversize = 0; -#endif /* TCP_OVERSIZE */ - } -} - -/** - * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. - * - * @param pcblist PCB list to purge. - * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated! - */ -void -tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) -{ - TCP_RMV(pcblist, pcb); - - tcp_pcb_purge(pcb); - - /* if there is an outstanding delayed ACKs, send it */ - if (pcb->state != TIME_WAIT && - pcb->state != LISTEN && - pcb->flags & TF_ACK_DELAY) { - pcb->flags |= TF_ACK_NOW; - tcp_output(pcb); - } - - if (pcb->state != LISTEN) { - LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL); - LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL); -#if TCP_QUEUE_OOSEQ - LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL); -#endif /* TCP_QUEUE_OOSEQ */ - } - - pcb->state = CLOSED; - - LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); -} - -/** - * Calculates a new initial sequence number for new connections. - * - * @return u32_t pseudo random sequence number - */ -u32_t -tcp_next_iss(void) -{ - static u32_t iss = 6510; - - again: - iss += tcp_ticks; /* XXX */ - if (iss == 0) - goto again; - - return iss; -} - -#if TCP_CALCULATE_EFF_SEND_MSS -/** - * Calcluates the effective send mss that can be used for a specific IP address - * by using ip_route to determin the netif used to send to the address and - * calculating the minimum of TCP_MSS and that netif's mtu (if set). - */ -u16_t -tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr) -{ - u16_t mss_s; - struct netif *outif; - - outif = ip_route(addr); - if ((outif != NULL) && (outif->mtu != 0)) { - mss_s = outif->mtu - IP_HLEN - TCP_HLEN; - /* RFC 1122, chap 4.2.2.6: - * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize - * We correct for TCP options in tcp_write(), and don't support IP options. - */ - sendmss = LWIP_MIN(sendmss, mss_s); - } - return sendmss; -} -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - -#if TCP_DEBUG -const char* -tcp_debug_state_str(enum tcp_state s) -{ - system_get_string_from_flash(tcp_state_str_rodata[s], tcp_state_str, 12); - - return tcp_state_str; -} -#endif - -#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG -/** - * Print a tcp header for debugging purposes. - * - * @param tcphdr pointer to a struct tcp_hdr - */ -void -tcp_debug_print(struct tcp_hdr *tcphdr) -{ - LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n")); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", - ntohs(tcphdr->src), ntohs(tcphdr->dest))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n", - ntohl(tcphdr->seqno))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n", - ntohl(tcphdr->ackno))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (", - TCPH_HDRLEN(tcphdr), - TCPH_FLAGS(tcphdr) >> 5 & 1, - TCPH_FLAGS(tcphdr) >> 4 & 1, - TCPH_FLAGS(tcphdr) >> 3 & 1, - TCPH_FLAGS(tcphdr) >> 2 & 1, - TCPH_FLAGS(tcphdr) >> 1 & 1, - TCPH_FLAGS(tcphdr) & 1, - ntohs(tcphdr->wnd))); - tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); - LWIP_DEBUGF(TCP_DEBUG, ("), win)\n")); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n", - ntohs(tcphdr->chksum), ntohs(tcphdr->urgp))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); -} - -/** - * Print a tcp state for debugging purposes. - * - * @param s enum tcp_state to print - */ -void -tcp_debug_print_state(enum tcp_state s) -{ - LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s])); -} - -/** - * Print tcp flags for debugging purposes. - * - * @param flags tcp flags, all active flags are printed - */ -void -tcp_debug_print_flags(u8_t flags) -{ - if (flags & TCP_FIN) { - LWIP_DEBUGF(TCP_DEBUG, ("FIN ")); - } - if (flags & TCP_SYN) { - LWIP_DEBUGF(TCP_DEBUG, ("SYN ")); - } - if (flags & TCP_RST) { - LWIP_DEBUGF(TCP_DEBUG, ("RST ")); - } - if (flags & TCP_PSH) { - LWIP_DEBUGF(TCP_DEBUG, ("PSH ")); - } - if (flags & TCP_ACK) { - LWIP_DEBUGF(TCP_DEBUG, ("ACK ")); - } - if (flags & TCP_URG) { - LWIP_DEBUGF(TCP_DEBUG, ("URG ")); - } - if (flags & TCP_ECE) { - LWIP_DEBUGF(TCP_DEBUG, ("ECE ")); - } - if (flags & TCP_CWR) { - LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); - } - LWIP_DEBUGF(TCP_DEBUG, ("\n")); -} - -/** - * Print all tcp_pcbs in every list for debugging purposes. - */ -void -tcp_debug_print_pcbs(void) -{ - struct tcp_pcb *pcb; - LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n")); - for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", - pcb->local_port, pcb->remote_port, - pcb->snd_nxt, pcb->rcv_nxt)); - tcp_debug_print_state(pcb->state); - } - LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n")); - for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", - pcb->local_port, pcb->remote_port, - pcb->snd_nxt, pcb->rcv_nxt)); - tcp_debug_print_state(pcb->state); - } - LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n")); - for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", - pcb->local_port, pcb->remote_port, - pcb->snd_nxt, pcb->rcv_nxt)); - tcp_debug_print_state(pcb->state); - } -} - -/** - * Check state consistency of the tcp_pcb lists. - */ -s16_t -tcp_pcbs_sane(void) -{ - struct tcp_pcb *pcb; - for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED); - LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN); - LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); - } - for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); - } - return 1; -} -#endif /* TCP_DEBUG */ - -#endif /* LWIP_TCP */ diff --git a/tools/sdk/lwip/src/core/tcp_in.c b/tools/sdk/lwip/src/core/tcp_in.c deleted file mode 100644 index 409559605..000000000 --- a/tools/sdk/lwip/src/core/tcp_in.c +++ /dev/null @@ -1,1646 +0,0 @@ -/** - * @file - * Transmission Control Protocol, incoming traffic - * - * The input processing functions of the TCP layer. - * - * These functions are generally called in the order (ip_input() ->) - * tcp_input() -> * tcp_process() -> tcp_receive() (-> application). - * - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/tcp_impl.h" -#include "lwip/def.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/inet_chksum.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "arch/perf.h" - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -/* These variables are global to all functions involved in the input - processing of TCP segments. They are set by the tcp_input() - function. */ -static struct tcp_seg inseg; //tcp_seg�ṹ����������ı��Ķ� -static struct tcp_hdr *tcphdr; //������TCP�ײ� -static struct ip_hdr *iphdr; //IP��ݰ��ײ� -static u32_t seqno, ackno; //TCP�ײ�������ֶ���ȷ�Ϻ��ֶ� -static u8_t flags; //�ײ���־�ֶ� -static u16_t tcplen; //TCP���ij��� - -static u8_t recv_flags; //��ǰ���Ĵ����� -static struct pbuf *recv_data; //�������pbuf - -struct tcp_pcb *tcp_input_pcb; //��ǰ���Ŀ��ƿ� - -/* Forward declarations. */ -static err_t tcp_process(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; -static void tcp_receive(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; -static void tcp_parseopt(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; - -static err_t tcp_listen_input(struct tcp_pcb_listen *pcb)ICACHE_FLASH_ATTR; -static err_t tcp_timewait_input(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; - -/** - * The initial input processing of TCP. It verifies the TCP header, demultiplexes - * the segment between the PCBs and passes it on to tcp_process(), which implements - * the TCP finite state machine. This function is called by the IP layer (in - * ip_input()). - * - * @param p received TCP segment to process (p->payload pointing to the IP header) - * @param inp network interface on which this segment was received - */ - /** - * TCP��ʼ�����봦�?��֤��TCPͷ���������IP����� - - * @����p:������յ�TCP��(ָ��IPͷ�ĸ���) - * @����inp:���նε�����ӿ� - */ -void -tcp_input(struct pbuf *p, struct netif *inp) -{ - struct tcp_pcb *pcb, *prev; - struct tcp_pcb_listen *lpcb; -#if SO_REUSE - struct tcp_pcb *lpcb_prev = NULL; - struct tcp_pcb_listen *lpcb_any = NULL; -#endif /* SO_REUSE */ - u8_t hdrlen; - err_t err; - - PERF_START; - - TCP_STATS_INC(tcp.recv); //״̬��1 - snmp_inc_tcpinsegs(); //tcp����μ�1 - - iphdr = (struct ip_hdr *)p->payload;// pointer to the actual data in the buffer - /* - *��ͷ����(IHL)��4�IPЭ���ͷ�ij��ȣ�ָ��IPv4Э���ͷ���ȵ��ֽ������ٸ�32� - *����IPv4�İ�ͷ���ܰ�ɱ������Ŀ�ѡ ���������ֶο�������ȷ��IPv4��ݱ�����ݲ��ֵ�ƫ������ - *IPv4��ͷ����С������20���ֽڣ����IHL����ֶε���Сֵ��ʮ���Ʊ�ʾ����5 (5x4 = 20�ֽ�)�� - *����˵�����ʾ�İ�ͷ�����ֽ�����4�ֽڵı��� - */ - tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4); - -#if TCP_INPUT_DEBUG - tcp_debug_print(tcphdr); -#endif - - /* remove header from payload */ - if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) { - /* drop short packets */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); - TCP_STATS_INC(tcp.lenerr);//���󳤶ȼ��� - TCP_STATS_INC(tcp.drop);//��ֹ���� - snmp_inc_tcpinerrs(); - pbuf_free(p);//�ͷ�buffer - return; - } - - /* Don't even process incoming broadcasts/multicasts. */ - if (ip_addr_isbroadcast(¤t_iphdr_dest, inp) || - ip_addr_ismulticast(¤t_iphdr_dest)) { - TCP_STATS_INC(tcp.proterr);//�������� - TCP_STATS_INC(tcp.drop); - snmp_inc_tcpinerrs(); - pbuf_free(p); - return; - } - -#if CHECKSUM_CHECK_TCP - /* Verify TCP checksum. */ - if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), - IP_PROTO_TCP, p->tot_len) != 0) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", - inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), - IP_PROTO_TCP, p->tot_len))); -#if TCP_DEBUG - tcp_debug_print(tcphdr); -#endif /* TCP_DEBUG */ - TCP_STATS_INC(tcp.chkerr);//�������� - TCP_STATS_INC(tcp.drop); - snmp_inc_tcpinerrs(); - pbuf_free(p); - return; - } -#endif - - /* Move the payload pointer in the pbuf so that it points to the - TCP data instead of the TCP header. */ - hdrlen = TCPH_HDRLEN(tcphdr);//����ͷ�ij��� - if(pbuf_header(p, -(hdrlen * 4))){//���TCPͷ������0Ϊ�ɹ������� - /* drop short packets */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n")); - TCP_STATS_INC(tcp.lenerr);//tcp���ȴ������ - TCP_STATS_INC(tcp.drop); - snmp_inc_tcpinerrs(); - pbuf_free(p); - return; - } - - /* Convert fields in TCP header to host byte order. */ - tcphdr->src = ntohs(tcphdr->src); //ת��Դ��ַ - tcphdr->dest = ntohs(tcphdr->dest); //ת��Ŀ�ĵ�ַ - seqno = tcphdr->seqno = ntohl(tcphdr->seqno); //ת�����к� - ackno = tcphdr->ackno = ntohl(tcphdr->ackno); //ת��Ӧ��� - tcphdr->wnd = ntohs(tcphdr->wnd); //ת��tcp���� - - flags = TCPH_FLAGS(tcphdr);//�õ�tcp header�ı�־ - /* - *��־��3λ�����ֶΣ��� - * �����1λ - * ���ֶ�λ��1λ��ȡֵ��0��������ݱ��ֶΣ���1����ݱ����ֶܷΣ� - * �����1λ��ȡֵ��0����ݰ����û�а�1����ݰ�����и��İ� - */ - tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);//TCP_FIN �� TCP_SYN ���1�������0 - - /* Demultiplex an incoming segment. First, we check if it is destined - for an active connection. ���ȣ�����Ƿ�һ��Ҫ����һ������*/ - //////////////////////////////////////////////////////////////////////////////////////// - prev = NULL; - for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {//������б� - LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); - LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); - LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); - if (pcb->remote_port == tcphdr->src && - pcb->local_port == tcphdr->dest && - ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && - ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) {//�����صĵ�ַ - - /* Move this PCB to the front of the list so that subsequent - lookups will be faster (we exploit locality in TCP segment - arrivals). */ - LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); - if (prev != NULL) {//���ǰһ���ڵ㲻Ϊ�� - prev->next = pcb->next; - pcb->next = tcp_active_pcbs; - tcp_active_pcbs = pcb;//pcb������ǰ�� - } - LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); - break; - } - prev = pcb;//prevָ��pcb - } - - if (pcb == NULL) { - /* If it did not go to an active connection, we check the connections - in the TIME-WAIT state. */ - for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {//����ȴ�״̬�µ�pcb - LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); - if (pcb->remote_port == tcphdr->src && - pcb->local_port == tcphdr->dest && - ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && - ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) { - /* We don't really care enough to move this PCB to the front - of the list since we are not very likely to receive that - many segments for connections in TIME-WAIT. */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n")); - tcp_timewait_input(pcb);//����tcp timewait �� - pbuf_free(p); - return; - } - } - - /* Finally, if we still did not get a match, we check all PCBs that - are LISTENing for incoming connections. */ - prev = NULL; - for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {//�������״̬�����е�pcb - if (lpcb->local_port == tcphdr->dest) { -#if SO_REUSE - if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest)) { - /* found an exact match */ - break; - } else if(ip_addr_isany(&(lpcb->local_ip))) { - /* found an ANY-match */ - lpcb_any = lpcb; - lpcb_prev = prev; - } -#else /* SO_REUSE */ - if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest) || - ip_addr_isany(&(lpcb->local_ip))) { - /* found a match */ - break; - } -#endif /* SO_REUSE */ - } - prev = (struct tcp_pcb *)lpcb; - } -#if SO_REUSE - /* first try specific local IP */ - if (lpcb == NULL) { - /* only pass to ANY if no specific local IP has been found */ - lpcb = lpcb_any; - prev = lpcb_prev; - } -#endif /* SO_REUSE */ - if (lpcb != NULL) { - /* Move this PCB to the front of the list so that subsequent - lookups will be faster (we exploit locality in TCP segment - arrivals). */ - if (prev != NULL) { - ((struct tcp_pcb_listen *)prev)->next = lpcb->next; - /* our successor is the remainder of the listening list */ - lpcb->next = tcp_listen_pcbs.listen_pcbs; - /* put this listening pcb at the head of the listening list */ - tcp_listen_pcbs.listen_pcbs = lpcb; - } - - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); - tcp_listen_input(lpcb);//����tcp������ݰ� - pbuf_free(p); - return; - } - } - -#if TCP_INPUT_DEBUG - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ")); - tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n")); -#endif /* TCP_INPUT_DEBUG */ - - - if (pcb != NULL) { - /* The incoming segment belongs to a connection. */ -#if TCP_INPUT_DEBUG -#if TCP_DEBUG - tcp_debug_print_state(pcb->state); -#endif /* TCP_DEBUG */ -#endif /* TCP_INPUT_DEBUG */ - - /* Set up a tcp_seg structure. */ - inseg.next = NULL; - inseg.len = p->tot_len; - inseg.p = p; - inseg.tcphdr = tcphdr; - - recv_data = NULL; - recv_flags = 0; - - /* If there is data which was previously "refused" by upper layer */ - if (pcb->refused_data != NULL) { - /* Notify again application with data previously received. */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); - TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);//pcb������� - if (err == ERR_OK) { - pcb->refused_data = NULL; - } else if ((err == ERR_ABRT) || (tcplen > 0)) { - /* if err == ERR_ABRT, 'pcb' is already deallocated */ - /* Drop incoming packets because pcb is "full" (only if the incoming - segment contains data). */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); - TCP_STATS_INC(tcp.drop);//tcp������� - snmp_inc_tcpinerrs(); - pbuf_free(p); - return; - } - } - tcp_input_pcb = pcb;//��¼��ǰ���Ĵ���Ŀ��ƿ� - err = tcp_process(pcb);//���?�� - /* A return value of ERR_ABRT means that tcp_abort() was called - and that the pcb has been freed. If so, we don't do anything. */ - if (err != ERR_ABRT) { - if (recv_flags & TF_RESET) { - /* TF_RESET means that the connection was reset by the other - end. We then call the error callback to inform the - application that the connection is dead before we - deallocate the PCB. */ - TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST); - tcp_pcb_remove(&tcp_active_pcbs, pcb);//ɾ���pcb�б��е�pcb - memp_free(MEMP_TCP_PCB, pcb); - } else if (recv_flags & TF_CLOSED) { - /* The connection has been closed and we will deallocate the - PCB. */ - if (!(pcb->flags & TF_RXCLOSED)) { - /* Connection closed although the application has only shut down the - tx side: call the PCB's err callback and indicate the closure to - ensure the application doesn't continue using the PCB. */ - TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_CLSD); - } - tcp_pcb_remove(&tcp_active_pcbs, pcb); - memp_free(MEMP_TCP_PCB, pcb); - } else { - err = ERR_OK; - /* If the application has registered a "sent" function to be - called when new send buffer space is available, we call it - now. */ - if (pcb->acked > 0) { - TCP_EVENT_SENT(pcb, pcb->acked, err);//����ݱ�ȷ�ϣ��ص��û���send���� - if (err == ERR_ABRT) { - goto aborted; - } - } - - if (recv_data != NULL) {//����ݽ��յ� - LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL); - if (pcb->flags & TF_RXCLOSED) { - /* received data although already closed -> abort (send RST) to - notify the remote host that not all data has been processed */ - pbuf_free(recv_data); - tcp_abort(pcb); - goto aborted; - } - - //PSH��־ PSH ����� - //��PSH=1ʱ��Ҫ���ͷ����Ϸ��͸÷ֶΣ� - //����շ�����Ľ����Ľ���Ӧ�ò㣬�������д��? - - if (flags & TCP_PSH) { - recv_data->flags |= PBUF_FLAG_PUSH;//���bufferӦ������������ - } - - /* Notify application that data has been received. */ - TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); - if (err == ERR_ABRT) { - goto aborted; - } - - /* If the upper layer can't receive this data, store it */ - if (err != ERR_OK) { - pcb->refused_data = recv_data; - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); - } - } - - /* If a FIN segment was received, we call the callback - function with a NULL buffer to indicate EOF. */ - if (recv_flags & TF_GOT_FIN) { - /* correct rcv_wnd as the application won't call tcp_recved() - for the FIN's seqno */ - if (pcb->rcv_wnd != TCP_WND) { - pcb->rcv_wnd++; - } - - TCP_EVENT_CLOSED(pcb, err); - if (err == ERR_ABRT) { - goto aborted; - } - } - - tcp_input_pcb = NULL;//���ȫ�ֱ��� - /* Try to send something out. */ - tcp_output(pcb);//����������� -#if TCP_INPUT_DEBUG -#if TCP_DEBUG - tcp_debug_print_state(pcb->state); -#endif /* TCP_DEBUG */ -#endif /* TCP_INPUT_DEBUG */ - } - } - /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()). - Below this line, 'pcb' may not be dereferenced! */ -aborted: - tcp_input_pcb = NULL; - recv_data = NULL; - - /* give up our reference to inseg.p */ - if (inseg.p != NULL) - { - pbuf_free(inseg.p);//�ͷ�buffer - inseg.p = NULL; - } - - /*add processing queue segments that arrive out of order by LiuHan*/ -#if TCP_QUEUE_OOSEQ - extern char RxNodeNum(void); - if (RxNodeNum() < 2){ - extern void pbuf_free_ooseq_new(void* arg); -// os_printf("reclaim some memory from queued\n"); - pbuf_free_ooseq_new(NULL); - } -#endif - } else { - - /* If no matching PCB was found, send a TCP RST (reset) to the - sender. */ - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); - if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { - TCP_STATS_INC(tcp.proterr);//�������� - TCP_STATS_INC(tcp.drop);//tcp������� - tcp_rst(ackno, seqno + tcplen, - ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src);//����TCP��λ - } - pbuf_free(p); - } - - LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); - PERF_STOP("tcp_input"); -} - -/** - * Called by tcp_input() when a segment arrives for a listening - * connection (from tcp_input()). - * - * @param pcb the tcp_pcb_listen for which a segment arrived - * @return ERR_OK if the segment was processed - * another err_t on error - * - * @note the return value is not (yet?) used in tcp_input() - * @note the segment which arrived is saved in global variables, therefore only the pcb - * involved is passed as a parameter to this function - */ - /* -*����LISTEN״̬�Ŀ��ƿ���øú��� -*ͨ���Ƿ�������������һ���˿ڲ�����ͻ���SYN�������� -* -*/ -static err_t -tcp_listen_input(struct tcp_pcb_listen *pcb) -{ - struct tcp_pcb *npcb; - struct tcp_pcb *pactive_pcb; - u8_t active_pcb_num = 0; - err_t rc; - - /* In the LISTEN state, we check for incoming SYN segments, - creates a new PCB, and responds with a SYN|ACK. */ - if (flags & TCP_ACK) { - /* For incoming segments with the ACK flag set, respond with a - RST. */ - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); - tcp_rst(ackno + 1, seqno + tcplen, - ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); - } else if (flags & TCP_SYN) {//�յ�SYN���� - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); -#if TCP_LISTEN_BACKLOG - if (pcb->accepts_pending >= pcb->backlog) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); - return ERR_ABRT; - } -#endif /* TCP_LISTEN_BACKLOG */ - for(pactive_pcb = tcp_active_pcbs; pactive_pcb != NULL; pactive_pcb = pactive_pcb->next){ - if (pactive_pcb->state == ESTABLISHED){ - active_pcb_num ++; - } - } - if (active_pcb_num == MEMP_NUM_TCP_PCB){ - LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: exceed the number of active TCP connections\n")); - TCP_STATS_INC(tcp.memerr); - return ERR_MEM; - } - npcb = tcp_alloc(pcb->prio);//�������ƿ� - /* If a new PCB could not be created (probably due to lack of memory), - we don't do anything, but rely on the sender will retransmit the - SYN at a time when we have more memory available. */ - if (npcb == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); - TCP_STATS_INC(tcp.memerr);//TCP�ڴ������� - return ERR_MEM; - } - -#if TCP_LISTEN_BACKLOG - pcb->accepts_pending++; -#endif /* TCP_LISTEN_BACKLOG */ - /* Set up the new PCB. */ - //���ƿ���������ص�4���ֶ� - ip_addr_copy(npcb->local_ip, current_iphdr_dest); - npcb->local_port = pcb->local_port; - ip_addr_copy(npcb->remote_ip, current_iphdr_src); - npcb->remote_port = tcphdr->src; - - //���ƿ��������ֶ� - npcb->state = SYN_RCVD;//��������״̬ - npcb->rcv_nxt = seqno + 1;//������һ������������ - npcb->rcv_ann_right_edge = npcb->rcv_nxt; - npcb->snd_wnd = tcphdr->wnd;//���÷��ʹ��� - npcb->ssthresh = npcb->snd_wnd; - npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ - npcb->callback_arg = pcb->callback_arg; -#if LWIP_CALLBACK_API - npcb->accept = pcb->accept; -#endif /* LWIP_CALLBACK_API */ - /* inherit socket options */ - npcb->so_options = pcb->so_options & SOF_INHERITED; - /* Register the new PCB so that we can begin receiving segments - for it. */ - TCP_REG(&tcp_active_pcbs, npcb); - - /* Parse any options in the SYN. */ - tcp_parseopt(npcb); -#if TCP_CALCULATE_EFF_SEND_MSS - npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip)); -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - - snmp_inc_tcppassiveopens(); - - /* Send a SYN|ACK together with the MSS option. */ - rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); - if (rc != ERR_OK) {//��������ͷ��¿��ƿ� - tcp_abandon(npcb, 0); - return rc; - } - return tcp_output(npcb);//���ͱ��� - } - return ERR_OK; -} - -/** - * Called by tcp_input() when a segment arrives for a connection in - * TIME_WAIT. - * - * @param pcb the tcp_pcb for which a segment arrived - * - * @note the segment which arrived is saved in global variables, therefore only the pcb - * involved is passed as a parameter to this function - */ - /* -*����TIME_WAIT״̬�Ŀ��ƿ���øú������յ��ı��ĶΣ� -*��״̬�£��ر����ӵ����ֹ���Ѿ��������ڵȴ�2MSL��ʱ�� -*��״̬�µı��Ķ����������еľ���ݣ�ֱ��ɾ��ɡ� -*����Ҫ���ͷ�����ACK���� -*/ -static err_t -tcp_timewait_input(struct tcp_pcb *pcb) -{ - - if (flags & TCP_RST) { //RST��λ��ֱ�ӷ��� - return ERR_OK; - } - - if (flags & TCP_SYN) { //��SYN������Ϣ����������ݱ���ڽ��մ����ڣ����ͷ�����RST���� - - if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) { - - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); - return ERR_OK; - } - } else if (flags & TCP_FIN) { //����FIN������Ϣ - - pcb->tmr = tcp_ticks; //��λ�ȴ�2MSLʱ�䣬���ƿ����µȴ�2MSL - } - - if ((tcplen > 0)) { //��������ݵı��Ļ����ڽ��մ������SYN���� - pcb->flags |= TF_ACK_NOW;//����һ��ACK���� - return tcp_output(pcb); - } - return ERR_OK; -} - -/** - * Implements the TCP state machine. Called by tcp_input. In some - * states tcp_receive() is called to receive data. The tcp_seg - * argument will be freed by the caller (tcp_input()) unless the - * recv_data pointer in the pcb is set. - * - * @param pcb the tcp_pcb for which a segment arrived - * - * @note the segment which arrived is saved in global variables, therefore only the pcb - * involved is passed as a parameter to this function - */ -static err_t -tcp_process(struct tcp_pcb *pcb) -{ - struct tcp_seg *rseg; - u8_t acceptable = 0; - err_t err; - - err = ERR_OK; - - /* Process incoming RST segments. */ - if (flags & TCP_RST) { - /* First, determine if the reset is acceptable. */ - if (pcb->state == SYN_SENT) { - if (ackno == pcb->snd_nxt) { - acceptable = 1; - } - } else { - if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, - pcb->rcv_nxt+pcb->rcv_wnd)) { - acceptable = 1; - } - } - - if (acceptable) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); - LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); - recv_flags |= TF_RESET; - pcb->flags &= ~TF_ACK_DELAY; - return ERR_RST; - } else { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", - seqno, pcb->rcv_nxt)); - LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", - seqno, pcb->rcv_nxt)); - return ERR_OK; - } - } - - if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { - /* Cope with new connection attempt after remote end crashed */ - tcp_ack_now(pcb); - return ERR_OK; - } - - if ((pcb->flags & TF_RXCLOSED) == 0) { - /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */ - pcb->tmr = tcp_ticks; - } - pcb->keep_cnt_sent = 0; - - tcp_parseopt(pcb); - - /* Do different things depending on the TCP state. */ - switch (pcb->state) { - case SYN_SENT: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno, - pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno))); - /* received SYN ACK with expected sequence number? */ - if ((flags & TCP_ACK) && (flags & TCP_SYN) - && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) { - pcb->snd_buf++; - pcb->rcv_nxt = seqno + 1; - pcb->rcv_ann_right_edge = pcb->rcv_nxt; - pcb->lastack = ackno; - pcb->snd_wnd = tcphdr->wnd; - pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ - pcb->state = ESTABLISHED; - -#if TCP_CALCULATE_EFF_SEND_MSS - pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip)); -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - - /* Set ssthresh again after changing pcb->mss (already set in tcp_connect - * but for the default value of pcb->mss) */ - pcb->ssthresh = pcb->mss * 10; - - pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss); - LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0)); - --pcb->snd_queuelen; - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen)); - rseg = pcb->unacked; - pcb->unacked = rseg->next; - - /* If there's nothing left to acknowledge, stop the retransmit - timer, otherwise reset it to start again */ - if(pcb->unacked == NULL) - pcb->rtime = -1; - else { - pcb->rtime = 0; -// pcb->nrtx = 0; - } - pcb->nrtx = 0; - - tcp_seg_free(rseg); - - /* Call the user specified function to call when sucessfully - * connected. */ - TCP_EVENT_CONNECTED(pcb, ERR_OK, err); - if (err == ERR_ABRT) { - return ERR_ABRT; - } - tcp_ack_now(pcb); - } - /* received ACK? possibly a half-open connection */ - else if (flags & TCP_ACK) { - /* send a RST to bring the other side in a non-synchronized state. */ - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); - } - break; - case SYN_RCVD: - if (flags & TCP_ACK) { - /* expected ACK number? */ - if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) { - u16_t old_cwnd; - pcb->state = ESTABLISHED; - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); -#if LWIP_CALLBACK_API - LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL); -#endif - /* Call the accept function. */ - TCP_EVENT_ACCEPT(pcb, ERR_OK, err); - if (err != ERR_OK) { - /* If the accept function returns with an error, we abort - * the connection. */ - /* Already aborted? */ - if (err != ERR_ABRT) { - tcp_abort(pcb); - } - return ERR_ABRT; - } - old_cwnd = pcb->cwnd; - /* If there was any data contained within this ACK, - * we'd better pass it on to the application as well. */ - tcp_receive(pcb); - - /* Prevent ACK for SYN to generate a sent event */ - if (pcb->acked != 0) { - pcb->acked--; - } - - pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss); - - if (recv_flags & TF_GOT_FIN) { - tcp_ack_now(pcb); - pcb->state = CLOSE_WAIT; - } - } else { - /* incorrect ACK number, send RST */ - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); - } - } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { - /* Looks like another copy of the SYN - retransmit our SYN-ACK */ - tcp_rexmit(pcb); - } - break; - case CLOSE_WAIT: - /* FALLTHROUGH */ - case ESTABLISHED: - tcp_receive(pcb); - if (recv_flags & TF_GOT_FIN) { /* passive close */ - tcp_ack_now(pcb); - pcb->state = CLOSE_WAIT; - } - break; - case FIN_WAIT_1: - tcp_receive(pcb); - if (recv_flags & TF_GOT_FIN) { - if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { - LWIP_DEBUGF(TCP_DEBUG, - ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_ack_now(pcb); - tcp_pcb_purge(pcb); - TCP_RMV(&tcp_active_pcbs, pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); - #if MEMP_NUM_TCP_PCB_TIME_WAIT - TCP_TW_LIMIT(MEMP_NUM_TCP_PCB_TIME_WAIT); - #endif - } else { - tcp_ack_now(pcb); - pcb->state = CLOSING; - } - } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { - pcb->state = FIN_WAIT_2; - } - break; - case FIN_WAIT_2: - tcp_receive(pcb); - if (recv_flags & TF_GOT_FIN) { - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_ack_now(pcb); - tcp_pcb_purge(pcb); - TCP_RMV(&tcp_active_pcbs, pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); -#if MEMP_NUM_TCP_PCB_TIME_WAIT - TCP_TW_LIMIT(MEMP_NUM_TCP_PCB_TIME_WAIT); -#endif - } - break; - case CLOSING: - tcp_receive(pcb); - if (flags & TCP_ACK && ackno == pcb->snd_nxt) { - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_pcb_purge(pcb); - TCP_RMV(&tcp_active_pcbs, pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); -#if MEMP_NUM_TCP_PCB_TIME_WAIT - TCP_TW_LIMIT(MEMP_NUM_TCP_PCB_TIME_WAIT); -#endif - } - break; - case LAST_ACK: - tcp_receive(pcb); - if (flags & TCP_ACK && ackno == pcb->snd_nxt) { - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ - recv_flags |= TF_CLOSED; - } - break; - default: - break; - } - return ERR_OK; -} - -#if TCP_QUEUE_OOSEQ -/** - * Insert segment into the list (segments covered with new one will be deleted) - * - * Called from tcp_receive() - */ -static void ICACHE_FLASH_ATTR -tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) -{ - struct tcp_seg *old_seg; - - if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { - /* received segment overlaps all following segments */ - tcp_segs_free(next); - next = NULL; - } - else { - /* delete some following segments - oos queue may have segments with FIN flag */ - while (next && - TCP_SEQ_GEQ((seqno + cseg->len), - (next->tcphdr->seqno + next->len))) { - /* cseg with FIN already processed */ - if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { - TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); - } - old_seg = next; - next = next->next; - tcp_seg_free(old_seg); - } - if (next && - TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { - /* We need to trim the incoming segment. */ - cseg->len = (u16_t)(next->tcphdr->seqno - seqno); - pbuf_realloc(cseg->p, cseg->len); - } - } - cseg->next = next; -} -#endif /* TCP_QUEUE_OOSEQ */ - -/** - * Called by tcp_process. Checks if the given segment is an ACK for outstanding - * data, and if so frees the memory of the buffered data. Next, is places the - * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment - * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until - * i it has been removed from the buffer. - * - * If the incoming segment constitutes an ACK for a segment that was used for RTT - * estimation, the RTT is estimated here as well. - * - * Called from tcp_process(). - */ -static void -tcp_receive(struct tcp_pcb *pcb) -{ - struct tcp_seg *next; -#if TCP_QUEUE_OOSEQ - struct tcp_seg *prev, *cseg; -#endif /* TCP_QUEUE_OOSEQ */ - struct pbuf *p; - s32_t off; - s16_t m; - u32_t right_wnd_edge; - u16_t new_tot_len; - int found_dupack = 0; - - if (flags & TCP_ACK) {//����ACK - right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;//���ʹ��� + ����Ӧ����󴰿ڸ��� - - // first /* Update window. */ - /*seqno > snd_wl1���������ֹ�̲��ô��ָ���; - *seqno = snd_wl1����ackno > snd_wl2;��ʱ���Է�û�з�����ݣ�ֻ���յ���ݵ�ȷ��; - *ackno = snd_wl2�ұ����ײ��б�snd_wnd���Ĵ���.����������Ӧֵ - */ - if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || - (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || - (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) { - pcb->snd_wnd = tcphdr->wnd; - pcb->snd_wl1 = seqno; - pcb->snd_wl2 = ackno; - if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) { - pcb->persist_backoff = 0;//�����ʱ���˳� - } - LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd)); -#if TCP_WND_DEBUG - } else { - if (pcb->snd_wnd != tcphdr->wnd) { - LWIP_DEBUGF(TCP_WND_DEBUG, - ("tcp_receive: no window update lastack %"U32_F" ackno %" - U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", - pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); - } -#endif /* TCP_WND_DEBUG */ - } - - /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a - * duplicate ack if: - * 1) It doesn't ACK new data û��ȷ������� - * 2) length of received packet is zero (i.e. no payload) ���Ķ����κ���� - * 3) the advertised window hasn't changed ���ش���û�и��� - * 4) There is outstanding unacknowledged data (retransmission timer running)������ݵȴ�ȷ�� - * 5) The ACK is == biggest ACK sequence number so far seen (snd_una) ackno = lastack - * - * If it passes all five, should process as a dupack: - * a) dupacks < 3: do nothing - * b) dupacks == 3: fast retransmit - * c) dupacks > 3: increase cwnd - * - * If it only passes 1-3, should reset dupack counter (and add to - * stats, which we don't do in lwIP) - * - * If it only passes 1, should reset dupack counter - * - */ - - /* Clause 1 */ - if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {//���ظ�ACK? - pcb->acked = 0; - /* Clause 2 */ - if (tcplen == 0) { - /* Clause 3 */ - if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){ - /* Clause 4 */ - if (pcb->rtime >= 0) { - /* Clause 5 */ - if (pcb->lastack == ackno) { - found_dupack = 1; - if (pcb->dupacks + 1 > pcb->dupacks) - ++pcb->dupacks; - if (pcb->dupacks > 3) { - /* Inflate the congestion window, but not if it means that - the value overflows. */ - if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { - pcb->cwnd += pcb->mss; - } - } else if (pcb->dupacks == 3) {//���ظ�ACK - /* Do fast retransmit */ - tcp_rexmit_fast(pcb); - } - } - } - } - } - /* If Clause (1) or more is true, but not a duplicate ack, reset - * count of consecutive duplicate acks */ - if (!found_dupack) { - pcb->dupacks = 0; - } - } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){//ackno��lastack+1��snd_nxt֮�䣬�жϷ��ʹ�������� - /* We come here when the ACK acknowledges new data. */ - - if (pcb->flags & TF_INFR) { - pcb->flags &= ~TF_INFR;// Reset the "IN Fast Retransmit" flag,since we are no longer in fast retransmit - pcb->cwnd = pcb->ssthresh;//Reset the congestion window to the "slow start threshold". - } - - /* Reset the number of retransmissions. */ - pcb->nrtx = 0; - - /* Reset the retransmission time-out. */ - pcb->rto = (pcb->sa >> 3) + pcb->sv; - - /* Update the send buffer space. Diff between the two can never exceed 64K? */ - pcb->acked = (u16_t)(ackno - pcb->lastack); - - pcb->snd_buf += pcb->acked; - - /* Reset the fast retransmit variables. */ - pcb->dupacks = 0; - pcb->lastack = ackno; - - /* Update the congestion control variables (cwnd and - ssthresh). */ - if (pcb->state >= ESTABLISHED) {//״̬Ϊ�������ӱ�־ - if (pcb->cwnd < pcb->ssthresh) { - if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { - pcb->cwnd += pcb->mss; - } - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd)); - } else { - u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd); - if (new_cwnd > pcb->cwnd) { - pcb->cwnd = new_cwnd; - } - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd)); - } - } - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n", - ackno, - pcb->unacked != NULL? - ntohl(pcb->unacked->tcphdr->seqno): 0, - pcb->unacked != NULL? - ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0)); - - /* Remove segment from the unacknowledged list if the incoming - ACK acknowlegdes them. - *�ͷ�unacked�����ϱ�ȷ�ϵı��ĶΣ� - *ֱ��unacked����Ϊ��ֹͣ*/ - while (pcb->unacked != NULL && - TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) + - TCP_TCPLEN(pcb->unacked), ackno)) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n", - ntohl(pcb->unacked->tcphdr->seqno), - ntohl(pcb->unacked->tcphdr->seqno) + - TCP_TCPLEN(pcb->unacked))); - - next = pcb->unacked;//pcb unacked��־ - pcb->unacked = pcb->unacked->next;//pcb unacked ��һ����־ - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); - LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); - /* Prevent ACK for FIN to generate a sent event */ - if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { - pcb->acked--; - } - - pcb->snd_queuelen -= pbuf_clen(next->p);//�������������pbufs���� - tcp_seg_free(next);//�ͷ�tcp�� - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen)); - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || - pcb->unsent != NULL); - } - } - - /* If there's nothing left to acknowledge, stop the retransmit - timer, otherwise reset it to start again */ - if(pcb->unacked == NULL) //����ݵȴ�ȷ�� - pcb->rtime = -1; //ֹͣ�ش���ʱ�� - else - pcb->rtime = 0; //��λ�ش���ʱ�� - - pcb->polltmr = 0; - } else { - /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */ - pcb->acked = 0; - } - - /* We go through the ->unsent list to see if any of the segments - on the list are acknowledged by the ACK. This may seem - strange since an "unsent" segment shouldn't be acked. The - rationale is that lwIP puts all outstanding segments on the - ->unsent list after a retransmission, so these segments may - in fact have been sent once. */ - /** unsent�������Ƿ��ܱ�acknoȷ�ϵı��ĶΣ������ͷ�**/ - while (pcb->unsent != NULL && - TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + - TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n", - ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) + - TCP_TCPLEN(pcb->unsent))); - - next = pcb->unsent;//pcbδ���ͱ�־ - pcb->unsent = pcb->unsent->next;//δ���͵���һ�� - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); - LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); - /* Prevent ACK for FIN to generate a sent event */ - if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { - pcb->acked--; - } - pcb->snd_queuelen -= pbuf_clen(next->p);//������pbuf�ĸ��� - tcp_seg_free(next);//�ͷŶ� - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen)); - if (pcb->snd_queuelen != 0) {//��������� - LWIP_ASSERT("tcp_receive: valid queue length", - pcb->unacked != NULL || pcb->unsent != NULL); - } - } - /* End of ACK for new data processing. */ - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", - pcb->rttest, pcb->rtseq, ackno)); - - /* RTT estimation calculations. This is done by checking if the - incoming segment acknowledges the segment we use to take a - round-trip time measurement. */ - if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {//RTT���ڽ����Ҹñ��Ķα�ȷ�� - /* diff between this shouldn't exceed 32K since this are tcp timer ticks - and a round-trip shouldn't be that long... */ - m = (s16_t)(tcp_ticks - pcb->rttest);//����MÖµ - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", - m, m * TCP_SLOW_INTERVAL)); - - /* This is taken directly from VJs original code in his paper �����RTT���㹫ʽ*/ - m = m - (pcb->sa >> 3); - pcb->sa += m; - if (m < 0) { - m = -m; - } - m = m - (pcb->sv >> 2); - pcb->sv += m; - pcb->rto = (pcb->sa >> 3) + pcb->sv; - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", - pcb->rto, pcb->rto * TCP_SLOW_INTERVAL)); - - pcb->rttest = 0; - } - } - - /* If the incoming segment contains data, we must process it - further. */ - if (tcplen > 0) { - /* This code basically does three things: - - +) If the incoming segment contains data that is the next - in-sequence data, this data is passed to the application. This - might involve trimming the first edge of the data. The rcv_nxt - variable and the advertised window are adjusted. - - +) If the incoming segment has data that is above the next - sequence number expected (->rcv_nxt), the segment is placed on - the ->ooseq queue. This is done by finding the appropriate - place in the ->ooseq queue (which is ordered by sequence - number) and trim the segment in both ends if needed. An - immediate ACK is sent to indicate that we received an - out-of-sequence segment. - - +) Finally, we check if the first segment on the ->ooseq queue - now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If - rcv_nxt > ooseq->seqno, we must trim the first edge of the - segment on ->ooseq before we adjust rcv_nxt. The data in the - segments that are now on sequence are chained onto the - incoming segment so that we only need to call the application - once. - */ - - /* First, we check if we must trim the first edge. We have to do - this if the sequence number of the incoming segment is less - than rcv_nxt, and the sequence number plus the length of the - segment is larger than rcv_nxt. */ - /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ - if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ - if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){// seqno < rcv_nxt < seqno + tcplen - /* Trimming the first edge is done by pushing the payload - pointer in the pbuf downwards. This is somewhat tricky since - we do not want to discard the full contents of the pbuf up to - the new starting point of the data since we have to keep the - TCP header which is present in the first pbuf in the chain. - - What is done is really quite a nasty hack: the first pbuf in - the pbuf chain is pointed to by inseg.p. Since we need to be - able to deallocate the whole pbuf, we cannot change this - inseg.p pointer to point to any of the later pbufs in the - chain. Instead, we point the ->payload pointer in the first - pbuf to data in one of the later pbufs. We also set the - inseg.data pointer to point to the right place. This way, the - ->p pointer will still point to the first pbuf, but the - ->p->payload pointer will point to data in another pbuf. - - After we are done with adjusting the pbuf pointers we must - adjust the ->data pointer in the seg and the segment - length.*/ - //ȥ�����Ķ�����ݱ�ŵ���rcv_nxt����� - off = pcb->rcv_nxt - seqno; - p = inseg.p; - LWIP_ASSERT("inseg.p != NULL", inseg.p); - LWIP_ASSERT("insane offset!", (off < 0x7fff)); - if (inseg.p->len < off) { - LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); - new_tot_len = (u16_t)(inseg.p->tot_len - off); - while (p->len < off) { - off -= p->len; - /* KJM following line changed (with addition of new_tot_len var) - to fix bug #9076 - inseg.p->tot_len -= p->len; */ - p->tot_len = new_tot_len; - p->len = 0; - p = p->next; - } - if(pbuf_header(p, (s16_t)-off)) { - /* Do we need to cope with this failing? Assert for now */ - LWIP_ASSERT("pbuf_header failed", 0); - } - } else { - if(pbuf_header(inseg.p, (s16_t)-off)) { - /* Do we need to cope with this failing? Assert for now */ - LWIP_ASSERT("pbuf_header failed", 0); - } - } - inseg.len -= (u16_t)(pcb->rcv_nxt - seqno); - inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; - } - else { - if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){//seqno < rcv_nxt - /* the whole segment is < rcv_nxt */ - /* must be a duplicate of a packet that has already been correctly handled */ - //���Ķ���������ݱ�ž�С��rcv_nxt����˱������ظ����ģ� - //ֱ����Դ����ӦACK���Ĵ��� - - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); - tcp_ack_now(pcb); - } - } - - /* The sequence number must be within the window (above rcv_nxt - and below rcv_nxt + rcv_wnd) in order to be further - processed. */ - if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, - pcb->rcv_nxt + pcb->rcv_wnd - 1)){//rcv_nxt < seqno < rcv_nxt + rcv_wnd - 1,������ڽ��շ�Χ�� - if (pcb->rcv_nxt == seqno) { - /* The incoming segment is the next in sequence. We check if - we have to trim the end of the segment and update rcv_nxt - and pass the data to the application. */ - tcplen = TCP_TCPLEN(&inseg);//���㱨�Ķγ��� - - if (tcplen > pcb->rcv_wnd) {//������մ��ڴ�С��������β���ض� - LWIP_DEBUGF(TCP_INPUT_DEBUG, - ("tcp_receive: other end overran receive window" - "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", - seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); - if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { - /* Must remove the FIN from the header as we're trimming - * that byte of sequence-space from the packet */ - TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN); - } - /* Adjust length of segment to fit in the window. */ - inseg.len = pcb->rcv_wnd; - if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { - inseg.len -= 1; - } - pbuf_realloc(inseg.p, inseg.len); - tcplen = TCP_TCPLEN(&inseg); - LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", - (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); - } -#if TCP_QUEUE_OOSEQ - /* Received in-sequence data, adjust ooseq data if: - - FIN has been received or - - inseq overlaps with ooseq */ - if (pcb->ooseq != NULL) { - if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, - ("tcp_receive: received in-order FIN, binning ooseq queue\n")); - /* Received in-order FIN means anything that was received - * out of order must now have been received in-order, so - * bin the ooseq queue */ - while (pcb->ooseq != NULL) { - struct tcp_seg *old_ooseq = pcb->ooseq; - pcb->ooseq = pcb->ooseq->next; - tcp_seg_free(old_ooseq); - } - } - else { - next = pcb->ooseq; - /* Remove all segments on ooseq that are covered by inseg already. - * FIN is copied from ooseq to inseg if present. */ - while (next && - TCP_SEQ_GEQ(seqno + tcplen, - next->tcphdr->seqno + next->len)) { - /* inseg cannot have FIN here (already processed above) */ - if (TCPH_FLAGS(next->tcphdr) & TCP_FIN && - (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { - TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); - tcplen = TCP_TCPLEN(&inseg); - } - prev = next; - next = next->next; - tcp_seg_free(prev); - } - /* Now trim right side of inseg if it overlaps with the first - * segment on ooseq */ - if (next && - TCP_SEQ_GT(seqno + tcplen, - next->tcphdr->seqno)) { - /* inseg cannot have FIN here (already processed above) */ - inseg.len = (u16_t)(next->tcphdr->seqno - seqno); - if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { - inseg.len -= 1; - } - pbuf_realloc(inseg.p, inseg.len); - tcplen = TCP_TCPLEN(&inseg); - LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", - (seqno + tcplen) == next->tcphdr->seqno); - } - pcb->ooseq = next; - } - } -#endif /* TCP_QUEUE_OOSEQ */ - - pcb->rcv_nxt = seqno + tcplen; - - /* Update the receiver's (our) window. */ - LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); - pcb->rcv_wnd -= tcplen; - - tcp_update_rcv_ann_wnd(pcb); - - /* If there is data in the segment, we make preparations to - pass this up to the application. The ->recv_data variable - is used for holding the pbuf that goes to the - application. The code for reassembling out-of-sequence data - chains its data on this pbuf as well. - - If the segment was a FIN, we set the TF_GOT_FIN flag that will - be used to indicate to the application that the remote side has - closed its end of the connection. */ - if (inseg.p->tot_len > 0) { - recv_data = inseg.p; - /* Since this pbuf now is the responsibility of the - application, we delete our reference to it so that we won't - (mistakingly) deallocate it. */ - inseg.p = NULL; - } - if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); - recv_flags |= TF_GOT_FIN; - } - -#if TCP_QUEUE_OOSEQ - /* We now check if we have segments on the ->ooseq queue that - are now in sequence. */ - while (pcb->ooseq != NULL && - pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { - - cseg = pcb->ooseq; - seqno = pcb->ooseq->tcphdr->seqno; - - pcb->rcv_nxt += TCP_TCPLEN(cseg); - LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", - pcb->rcv_wnd >= TCP_TCPLEN(cseg)); - pcb->rcv_wnd -= TCP_TCPLEN(cseg); - - tcp_update_rcv_ann_wnd(pcb); - - if (cseg->p->tot_len > 0) { - /* Chain this pbuf onto the pbuf that we will pass to - the application. */ - if (recv_data) { - pbuf_cat(recv_data, cseg->p); - } else { - recv_data = cseg->p; - } - cseg->p = NULL; - } - if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); - recv_flags |= TF_GOT_FIN; - if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ - pcb->state = CLOSE_WAIT; - } - } - - pcb->ooseq = cseg->next; - tcp_seg_free(cseg); - } -#endif /* TCP_QUEUE_OOSEQ */ - - - /* Acknowledge the segment(s). */ - tcp_ack(pcb); - - } else { - /* We get here if the incoming segment is out-of-sequence. */ - tcp_send_empty_ack(pcb); -#if TCP_QUEUE_OOSEQ - /* We queue the segment on the ->ooseq queue. */ - if (pcb->ooseq == NULL) { - pcb->ooseq = tcp_seg_copy(&inseg); - } else { - /* If the queue is not empty, we walk through the queue and - try to find a place where the sequence number of the - incoming segment is between the sequence numbers of the - previous and the next segment on the ->ooseq queue. That is - the place where we put the incoming segment. If needed, we - trim the second edges of the previous and the incoming - segment so that it will fit into the sequence. - - If the incoming segment has the same sequence number as a - segment on the ->ooseq queue, we discard the segment that - contains less data. */ - - prev = NULL; - for(next = pcb->ooseq; next != NULL; next = next->next) {//��ooseqȡ�µ�M�����ĶΣ��ñ��Ķηǿգ�M++ - if (seqno == next->tcphdr->seqno) {//�ñ��Ķ���ʼ���== Ҫ����ı��Ķα�� - /* The sequence number of the incoming segment is the - same as the sequence number of the segment on - ->ooseq. We check the lengths to see which one to - discard. */ - if (inseg.len > next->len) {//Ҫ����ı��Ķα�Ÿ� - /* The incoming segment is larger than the old - segment. We replace some segments with the new - one. */ - cseg = tcp_seg_copy(&inseg);//Ҫ����ı��Ķδ����M������ - if (cseg != NULL) { - if (prev != NULL) { - prev->next = cseg; - } else { - pcb->ooseq = cseg; - } - tcp_oos_insert_segment(cseg, next); - } - break; - } else { - /* Either the lenghts are the same or the incoming - segment was smaller than the old one; in either - case, we ditch the incoming segment. */ - break; - } - } else { - if (prev == NULL) { - if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { - /* The sequence number of the incoming segment is lower - than the sequence number of the first segment on the - queue. We put the incoming segment first on the - queue. */ - cseg = tcp_seg_copy(&inseg); - if (cseg != NULL) { - pcb->ooseq = cseg; - tcp_oos_insert_segment(cseg, next); - } - break; - } - } else { - /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && - TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ - if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) { - /* The sequence number of the incoming segment is in - between the sequence numbers of the previous and - the next segment on ->ooseq. We trim trim the previous - segment, delete next segments that included in received segment - and trim received, if needed. */ - cseg = tcp_seg_copy(&inseg); - if (cseg != NULL) { - if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { - /* We need to trim the prev segment. */ - prev->len = (u16_t)(seqno - prev->tcphdr->seqno); - pbuf_realloc(prev->p, prev->len); - } - prev->next = cseg; - tcp_oos_insert_segment(cseg, next); - } - break; - } - } - /* If the "next" segment is the last segment on the - ooseq queue, we add the incoming segment to the end - of the list. */ - if (next->next == NULL && - TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { - if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { - /* segment "next" already contains all data */ - break; - } - next->next = tcp_seg_copy(&inseg); - if (next->next != NULL) { - if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { - /* We need to trim the last segment. */ - next->len = (u16_t)(seqno - next->tcphdr->seqno); - pbuf_realloc(next->p, next->len); - } - /* check if the remote side overruns our receive window */ - if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, - ("tcp_receive: other end overran receive window" - "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", - seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); - if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) { - /* Must remove the FIN from the header as we're trimming - * that byte of sequence-space from the packet */ - TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN); - } - /* Adjust length of segment to fit in the window. */ - next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno; - pbuf_realloc(next->next->p, next->next->len); - tcplen = TCP_TCPLEN(next->next); - LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", - (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); - } - } - break; - } - } - prev = next; - } - } -#endif /* TCP_QUEUE_OOSEQ */ - - } - } else { - /* The incoming segment is not withing the window. */ - tcp_send_empty_ack(pcb); - } - } else { - /* Segments with length 0 is taken care of here. Segments that - fall out of the window are ACKed. */ - /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) || - TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/ - if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){ - tcp_ack_now(pcb);//��Դ�˷���һ������ȷ�ϱ��� - } - } -} - -/** - * Parses the options contained in the incoming segment. - * - * Called from tcp_listen_input() and tcp_process(). - * Currently, only the MSS option is supported! - * - * @param pcb the tcp_pcb for which a segment arrived - */ -static void -tcp_parseopt(struct tcp_pcb *pcb) -{ - u16_t c, max_c; - u16_t mss; - u8_t *opts, opt; -#if LWIP_TCP_TIMESTAMPS - u32_t tsval; -#endif - - opts = (u8_t *)tcphdr + TCP_HLEN; - - /* Parse the TCP MSS option, if present. */ - if(TCPH_HDRLEN(tcphdr) > 0x5) { - max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2; - for (c = 0; c < max_c; ) { - opt = opts[c]; - switch (opt) { - case 0x00: - /* End of options. */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); - return; - case 0x01: - /* NOP option. */ - ++c; - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); - break; - case 0x02: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); - if (opts[c + 1] != 0x04 || c + 0x04 > max_c) { - /* Bad length */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); - return; - } - /* An MSS option with the right option length. */ - mss = (opts[c + 2] << 8) | opts[c + 3]; - /* Limit the mss to the configured TCP_MSS and prevent division by zero */ - pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; - /* Advance to next option */ - c += 0x04; - break; -#if LWIP_TCP_TIMESTAMPS - case 0x08: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); - if (opts[c + 1] != 0x0A || c + 0x0A > max_c) { - /* Bad length */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); - return; - } - /* TCP timestamp option with valid length */ - tsval = (opts[c+2]) | (opts[c+3] << 8) | - (opts[c+4] << 16) | (opts[c+5] << 24); - if (flags & TCP_SYN) { - pcb->ts_recent = ntohl(tsval); - pcb->flags |= TF_TIMESTAMP; - } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) { - pcb->ts_recent = ntohl(tsval); - } - /* Advance to next option */ - c += 0x0A; - break; -#endif - default: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); - if (opts[c + 1] == 0) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); - /* If the length field is zero, the options are malformed - and we don't process them further. */ - return; - } - /* All other options have a length field, so that we easily - can skip past them. */ - c += opts[c + 1]; - } - } - } -} - -#endif /* LWIP_TCP */ diff --git a/tools/sdk/lwip/src/core/tcp_out.c b/tools/sdk/lwip/src/core/tcp_out.c deleted file mode 100644 index e2f8e9aa5..000000000 --- a/tools/sdk/lwip/src/core/tcp_out.c +++ /dev/null @@ -1,1525 +0,0 @@ -/** - * @file - * Transmission Control Protocol, outgoing traffic - * - * The output functions of TCP. - * - */ - -/* - * 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 - * - */ - -#include "lwip/opt.h" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/tcp_impl.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/sys.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/inet_chksum.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "netif/etharp.h" - -#include - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -/* Define some copy-macros for checksum-on-copy so that the code looks - nicer by preventing too many ifdef's. */ -#if TCP_CHECKSUM_ON_COPY -#define TCP_DATA_COPY(dst, src, len, seg) do { \ - tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \ - len, &seg->chksum, &seg->chksum_swapped); \ - seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0) -#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) \ - tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped); -#else /* TCP_CHECKSUM_ON_COPY*/ -#define TCP_DATA_COPY(dst, src, len, seg) MEMCPY(dst, src, len) -#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len) -#endif /* TCP_CHECKSUM_ON_COPY*/ - -/** Define this to 1 for an extra check that the output checksum is valid - * (usefule when the checksum is generated by the application, not the stack) */ -#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK -#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0 -#endif - -/* Forward declarations.*/ -static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); - -/** Allocate a pbuf and create a tcphdr at p->payload, used for output - * functions other than the default tcp_output -> tcp_output_segment - * (e.g. tcp_send_empty_ack, etc.) - * - * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr) - * @param optlen length of header-options - * @param datalen length of tcp data to reserve in pbuf - * @param seqno_be seqno in network byte order (big-endian) - * @return pbuf with p->payload being the tcp_hdr - */ -static struct pbuf *ICACHE_FLASH_ATTR -tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen, - u32_t seqno_be /* already in network byte order */) -{ - struct tcp_hdr *tcphdr; - struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM); - if (p != NULL) { - LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", - (p->len >= TCP_HLEN + optlen)); - tcphdr = (struct tcp_hdr *)p->payload; - tcphdr->src = htons(pcb->local_port); - tcphdr->dest = htons(pcb->remote_port); - tcphdr->seqno = seqno_be; - tcphdr->ackno = htonl(pcb->rcv_nxt); - TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK); - tcphdr->wnd = htons(pcb->rcv_ann_wnd); - tcphdr->chksum = 0; - tcphdr->urgp = 0; - - /* If we're sending a packet, update the announced right window edge */ - pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; - } - return p; -} - -/** - * Called by tcp_close() to send a segment including FIN flag but not data. - * - * @param pcb the tcp_pcb over which to send a segment - * @return ERR_OK if sent, another err_t otherwise - */ -err_t -tcp_send_fin(struct tcp_pcb *pcb) -{ - /* first, try to add the fin to the last unsent segment */ - if (pcb->unsent != NULL) { - struct tcp_seg *last_unsent; - for (last_unsent = pcb->unsent; last_unsent->next != NULL; - last_unsent = last_unsent->next); - - if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) { - /* no SYN/FIN/RST flag in the header, we can add the FIN flag */ - TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN); - return ERR_OK; - } - } - /* no data, no length, flags, copy=1, no optdata */ - return tcp_enqueue_flags(pcb, TCP_FIN); -} - -/** - * Create a TCP segment with prefilled header. - * - * Called by tcp_write and tcp_enqueue_flags. - * - * @param pcb Protocol control block for the TCP connection. - * @param p pbuf that is used to hold the TCP header. - * @param flags TCP flags for header. - * @param seqno TCP sequence number of this packet - * @param optflags options to include in TCP header - * @return a new tcp_seg pointing to p, or NULL. - * The TCP header is filled in except ackno and wnd. - * p is freed on failure. - */ -static struct tcp_seg *ICACHE_FLASH_ATTR -tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags) -{ - struct tcp_seg *seg; - u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags); - - if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n")); - pbuf_free(p); - return NULL; - } - seg->flags = optflags; - seg->next = NULL; - seg->p = p; - seg->len = p->tot_len - optlen; -#if TCP_OVERSIZE_DBGCHECK - seg->oversize_left = 0; -#endif /* TCP_OVERSIZE_DBGCHECK */ -#if TCP_CHECKSUM_ON_COPY - seg->chksum = 0; - seg->chksum_swapped = 0; - /* check optflags */ - LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED", - (optflags & TF_SEG_DATA_CHECKSUMMED) == 0); -#endif /* TCP_CHECKSUM_ON_COPY */ - - /* build TCP header */ - if (pbuf_header(p, TCP_HLEN)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n")); - TCP_STATS_INC(tcp.err); - tcp_seg_free(seg); - return NULL; - } - seg->tcphdr = (struct tcp_hdr *)seg->p->payload; - seg->tcphdr->src = htons(pcb->local_port); - seg->tcphdr->dest = htons(pcb->remote_port); - seg->tcphdr->seqno = htonl(seqno); - /* ackno is set in tcp_output */ - TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags); - /* wnd and chksum are set in tcp_output */ - seg->tcphdr->urgp = 0; - return seg; -} - -/** - * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end. - * - * This function is like pbuf_alloc(layer, length, PBUF_RAM) except - * there may be extra bytes available at the end. - * - * @param layer flag to define header size. - * @param length size of the pbuf's payload. - * @param max_length maximum usable size of payload+oversize. - * @param oversize pointer to a u16_t that will receive the number of usable tail bytes. - * @param pcb The TCP connection that willo enqueue the pbuf. - * @param apiflags API flags given to tcp_write. - * @param first_seg true when this pbuf will be used in the first enqueued segment. - * @param - */ -#if TCP_OVERSIZE -static struct pbuf *ICACHE_FLASH_ATTR -tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length, - u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags, - u8_t first_seg) -{ - struct pbuf *p; - u16_t alloc = length; - -#if LWIP_NETIF_TX_SINGLE_PBUF - LWIP_UNUSED_ARG(max_length); - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(apiflags); - LWIP_UNUSED_ARG(first_seg); - /* always create MSS-sized pbufs */ - alloc = TCP_MSS; -#else /* LWIP_NETIF_TX_SINGLE_PBUF */ - if (length < max_length) { - /* Should we allocate an oversized pbuf, or just the minimum - * length required? If tcp_write is going to be called again - * before this segment is transmitted, we want the oversized - * buffer. If the segment will be transmitted immediately, we can - * save memory by allocating only length. We use a simple - * heuristic based on the following information: - * - * Did the user set TCP_WRITE_FLAG_MORE? - * - * Will the Nagle algorithm defer transmission of this segment? - */ - if ((apiflags & TCP_WRITE_FLAG_MORE) || - (!(pcb->flags & TF_NODELAY) && - (!first_seg || - pcb->unsent != NULL || - pcb->unacked != NULL))) { - alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(length + TCP_OVERSIZE)); - } - } -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - p = pbuf_alloc(layer, alloc, PBUF_RAM); - if (p == NULL) { - return NULL; - } - LWIP_ASSERT("need unchained pbuf", p->next == NULL); - *oversize = p->len - length; - /* trim p->len to the currently used size */ - p->len = p->tot_len = length; - return p; -} -#else /* TCP_OVERSIZE */ -#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM) -#endif /* TCP_OVERSIZE */ - -#if TCP_CHECKSUM_ON_COPY -/** Add a checksum of newly added data to the segment */ -static void ICACHE_FLASH_ATTR -tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum, - u8_t *seg_chksum_swapped) -{ - u32_t helper; - /* add chksum to old chksum and fold to u16_t */ - helper = chksum + *seg_chksum; - chksum = FOLD_U32T(helper); - if ((len & 1) != 0) { - *seg_chksum_swapped = 1 - *seg_chksum_swapped; - chksum = SWAP_BYTES_IN_WORD(chksum); - } - *seg_chksum = chksum; -} -#endif /* TCP_CHECKSUM_ON_COPY */ - -/** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen). - * - * @param pcb the tcp pcb to check for - * @param len length of data to send (checked agains snd_buf) - * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise - */ -static err_t ICACHE_FLASH_ATTR -tcp_write_checks(struct tcp_pcb *pcb, u16_t len) -{ - /* connection is in invalid state for data transmission? */ - if ((pcb->state != ESTABLISHED) && - (pcb->state != CLOSE_WAIT) && - (pcb->state != SYN_SENT) && - (pcb->state != SYN_RCVD)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n")); - return ERR_CONN; - } else if (len == 0) { - return ERR_OK; - } - - /* fail on too much data */ - if (len > pcb->snd_buf) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", - len, pcb->snd_buf)); - pcb->flags |= TF_NAGLEMEMERR; - return ERR_MEM; - } - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); - - /* If total number of pbufs on the unsent/unacked queues exceeds the - * configured maximum, return an error */ - /* check for configured max queuelen and possible overflow */ - if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n", - pcb->snd_queuelen, TCP_SND_QUEUELEN)); - TCP_STATS_INC(tcp.memerr); - pcb->flags |= TF_NAGLEMEMERR; - return ERR_MEM; - } - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty", - pcb->unacked != NULL || pcb->unsent != NULL); - } else { - LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty", - pcb->unacked == NULL && pcb->unsent == NULL); - } - return ERR_OK; -} - -/** - * Write data for sending (but does not send it immediately). - *��������һ��������ݣ��ú�����һ�����Ķβ����ڿ��ƿ黺������� - * It waits in the expectation of more data being sent soon (as - * it can send them more efficiently by combining them together). - * To prompt the system to send data now, call tcp_output() after - * calling tcp_write(). - * - * @param pcb Protocol control block for the TCP connection to enqueue data for.��Ӧ���ӿ��ƿ� - * @param arg Pointer to the data to be enqueued for sending.���������ʼ��ַ - * @param len Data length in bytes������ݳ��� - * @param apiflags combination of following flags :����Ƿ���п������Լ����Ķ��ײ��Ƿ������PSH��־ - * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack - * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, - * @return ERR_OK if enqueued, another err_t on error - */ -err_t -tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) -{ - struct pbuf *concat_p = NULL; - struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL; - u16_t pos = 0; /* position in 'arg' data */ - u16_t queuelen; - u8_t optlen = 0; - u8_t optflags = 0; -#if TCP_OVERSIZE - u16_t oversize = 0; - u16_t oversize_used = 0; -#endif /* TCP_OVERSIZE */ -#if TCP_CHECKSUM_ON_COPY - u16_t concat_chksum = 0; - u8_t concat_chksum_swapped = 0; - u16_t concat_chksummed = 0; -#endif /* TCP_CHECKSUM_ON_COPY */ - err_t err; - -#if LWIP_NETIF_TX_SINGLE_PBUF - /* Always copy to try to create single pbufs for TX */ - apiflags |= TCP_WRITE_FLAG_COPY; -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", - (void *)pcb, arg, len, (u16_t)apiflags)); - LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)", - arg != NULL, return ERR_ARG;); - - err = tcp_write_checks(pcb, len); - if (err != ERR_OK) { - return err; - } - queuelen = pcb->snd_queuelen; - -#if LWIP_TCP_TIMESTAMPS - if ((pcb->flags & TF_TIMESTAMP)) { - optflags = TF_SEG_OPTS_TS; - optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); - } -#endif /* LWIP_TCP_TIMESTAMPS */ - - - /* - * TCP segmentation is done in three phases with increasing complexity: - * - * 1. Copy data directly into an oversized pbuf. - * 2. Chain a new pbuf to the end of pcb->unsent. - * 3. Create new segments. - * - * We may run out of memory at any point. In that case we must - * return ERR_MEM and not change anything in pcb. Therefore, all - * changes are recorded in local variables and committed at the end - * of the function. Some pcb fields are maintained in local copies: - * - * queuelen = pcb->snd_queuelen - * oversize = pcb->unsent_oversize - * - * These variables are set consistently by the phases: - * - * seg points to the last segment tampered with. - * - * pos records progress as data is segmented. - */ - - /* Find the tail of the unsent queue. */ - if (pcb->unsent != NULL) { - u16_t space; - u16_t unsent_optlen; - - /* @todo: this could be sped up by keeping last_unsent in the pcb */ - for (last_unsent = pcb->unsent; last_unsent->next != NULL; - last_unsent = last_unsent->next); - - /* Usable space at the end of the last unsent segment */ - unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags); - space = pcb->mss - (last_unsent->len + unsent_optlen); - - /* - * Phase 1: Copy data directly into an oversized pbuf. - * - * The number of bytes copied is recorded in the oversize_used - * variable. The actual copying is done at the bottom of the - * function. - */ -#if TCP_OVERSIZE -#if TCP_OVERSIZE_DBGCHECK - /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */ - LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)", - pcb->unsent_oversize == last_unsent->oversize_left); -#endif /* TCP_OVERSIZE_DBGCHECK */ - oversize = pcb->unsent_oversize; - if (oversize > 0) { - LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space); - seg = last_unsent; - oversize_used = oversize < len ? oversize : len; - pos += oversize_used; - oversize -= oversize_used; - space -= oversize_used; - } - /* now we are either finished or oversize is zero */ - LWIP_ASSERT("inconsistend oversize vs. len", (oversize == 0) || (pos == len)); -#endif /* TCP_OVERSIZE */ - - /* - * Phase 2: Chain a new pbuf to the end of pcb->unsent. - * - * We don't extend segments containing SYN/FIN flags or options - * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at - * the end. - */ - if ((pos < len) && (space > 0) && (last_unsent->len > 0)) { - u16_t seglen = space < len - pos ? space : len - pos; - seg = last_unsent; - - /* Create a pbuf with a copy or reference to seglen bytes. We - * can use PBUF_RAW here since the data appears in the middle of - * a segment. A header will never be prepended. */ - if (apiflags & TCP_WRITE_FLAG_COPY) { - /* Data is copied */ - if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, - ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", - seglen)); - goto memerr; - } -#if TCP_OVERSIZE_DBGCHECK - last_unsent->oversize_left = oversize; -#endif /* TCP_OVERSIZE_DBGCHECK */ - TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped); -#if TCP_CHECKSUM_ON_COPY - concat_chksummed += seglen; -#endif /* TCP_CHECKSUM_ON_COPY */ - } else { - /* Data is not copied */ - if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, - ("tcp_write: could not allocate memory for zero-copy pbuf\n")); - goto memerr; - } -#if TCP_CHECKSUM_ON_COPY - /* calculate the checksum of nocopy-data */ - tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen, - &concat_chksum, &concat_chksum_swapped); - concat_chksummed += seglen; -#endif /* TCP_CHECKSUM_ON_COPY */ - /* reference the non-volatile payload data */ - concat_p->payload = (u8_t*)arg + pos; - } - - pos += seglen; - queuelen += pbuf_clen(concat_p); - } - } else { -#if TCP_OVERSIZE - LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)", - pcb->unsent_oversize == 0); -#endif /* TCP_OVERSIZE */ - } - - /* - * Phase 3: Create new segments. - * - * The new segments are chained together in the local 'queue' - * variable, ready to be appended to pcb->unsent. - */ - while (pos < len) { - struct pbuf *p; - u16_t left = len - pos; - u16_t max_len = pcb->mss - optlen; - u16_t seglen = left > max_len ? max_len : left; -#if TCP_CHECKSUM_ON_COPY - u16_t chksum = 0; - u8_t chksum_swapped = 0; -#endif /* TCP_CHECKSUM_ON_COPY */ - - if (apiflags & TCP_WRITE_FLAG_COPY) { - /* If copy is set, memory should be allocated and data copied - * into pbuf */ - if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); - goto memerr; - } - LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen", - (p->len >= seglen)); - TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped); - } else { - /* Copy is not set: First allocate a pbuf for holding the data. - * Since the referenced data is available at least until it is - * sent out on the link (as it has to be ACKed by the remote - * party) we can safely use PBUF_ROM instead of PBUF_REF here. - */ - struct pbuf *p2; -#if TCP_OVERSIZE - LWIP_ASSERT("oversize == 0", oversize == 0); -#endif /* TCP_OVERSIZE */ - if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n")); - goto memerr; - } -#if TCP_CHECKSUM_ON_COPY - /* calculate the checksum of nocopy-data */ - chksum = ~inet_chksum((u8_t*)arg + pos, seglen); -#endif /* TCP_CHECKSUM_ON_COPY */ - /* reference the non-volatile payload data */ - p2->payload = (u8_t*)arg + pos; - - /* Second, allocate a pbuf for the headers. */ - if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { - /* If allocation fails, we have to deallocate the data pbuf as - * well. */ - pbuf_free(p2); - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for header pbuf\n")); - goto memerr; - } - /* Concatenate the headers and data pbufs together. */ - pbuf_cat(p/*header*/, p2/*data*/); - } - - queuelen += pbuf_clen(p); - - /* Now that there are more segments queued, we check again if the - * length of the queue exceeds the configured maximum or - * overflows. */ - if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); - pbuf_free(p); - goto memerr; - } - - if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { - goto memerr; - } -#if TCP_OVERSIZE_DBGCHECK - seg->oversize_left = oversize; -#endif /* TCP_OVERSIZE_DBGCHECK */ -#if TCP_CHECKSUM_ON_COPY - seg->chksum = chksum; - seg->chksum_swapped = chksum_swapped; - seg->flags |= TF_SEG_DATA_CHECKSUMMED; -#endif /* TCP_CHECKSUM_ON_COPY */ - - /* first segment of to-be-queued data? */ - if (queue == NULL) { - queue = seg; - } else { - /* Attach the segment to the end of the queued segments */ - LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL); - prev_seg->next = seg; - } - /* remember last segment of to-be-queued data for next iteration */ - prev_seg = seg; - - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n", - ntohl(seg->tcphdr->seqno), - ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); - - pos += seglen; - } - - /* - * All three segmentation phases were successful. We can commit the - * transaction. - */ - - /* - * Phase 1: If data has been added to the preallocated tail of - * last_unsent, we update the length fields of the pbuf chain. - */ -#if TCP_OVERSIZE - if (oversize_used > 0) { - struct pbuf *p; - /* Bump tot_len of whole chain, len of tail */ - for (p = last_unsent->p; p; p = p->next) { - p->tot_len += oversize_used; - if (p->next == NULL) { - TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent); - p->len += oversize_used; - } - } - last_unsent->len += oversize_used; -#if TCP_OVERSIZE_DBGCHECK - last_unsent->oversize_left -= oversize_used; -#endif /* TCP_OVERSIZE_DBGCHECK */ - } - pcb->unsent_oversize = oversize; -#endif /* TCP_OVERSIZE */ - - /* - * Phase 2: concat_p can be concatenated onto last_unsent->p - */ - if (concat_p != NULL) { - LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty", - (last_unsent != NULL)); - pbuf_cat(last_unsent->p, concat_p); - last_unsent->len += concat_p->tot_len; -#if TCP_CHECKSUM_ON_COPY - if (concat_chksummed) { - tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum, - &last_unsent->chksum_swapped); - last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED; - } -#endif /* TCP_CHECKSUM_ON_COPY */ - } - - /* - * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that - * is harmless - */ - if (last_unsent == NULL) { - pcb->unsent = queue; - } else { - last_unsent->next = queue; - } - - /* - * Finally update the pcb state. - */ - pcb->snd_lbb += len; - pcb->snd_buf -= len; - pcb->snd_queuelen = queuelen; - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n", - pcb->snd_queuelen)); - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_write: valid queue length", - pcb->unacked != NULL || pcb->unsent != NULL); - } - - /* Set the PSH flag in the last segment that we enqueued. */ - if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) { - TCPH_SET_FLAG(seg->tcphdr, TCP_PSH); - } - - return ERR_OK; -memerr: - pcb->flags |= TF_NAGLEMEMERR; - TCP_STATS_INC(tcp.memerr); - - if (concat_p != NULL) { - pbuf_free(concat_p); - } - if (queue != NULL) { - tcp_segs_free(queue); - } - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL || - pcb->unsent != NULL); - } - LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); - return ERR_MEM; -} - -/** - * Enqueue TCP options for transmission. - * - * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl(). - * - * @param pcb Protocol control block for the TCP connection. - * @param flags TCP header flags to set in the outgoing segment. - * @param optdata pointer to TCP options, or NULL. - * @param optlen length of TCP options in bytes. - */ -err_t -tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) -{ - struct pbuf *p; - struct tcp_seg *seg; - u8_t optflags = 0; - u8_t optlen = 0; - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); - - LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)", - (flags & (TCP_SYN | TCP_FIN)) != 0); - - /* check for configured max queuelen and possible overflow */ - if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n", - pcb->snd_queuelen, TCP_SND_QUEUELEN)); - TCP_STATS_INC(tcp.memerr); - pcb->flags |= TF_NAGLEMEMERR; - return ERR_MEM; - } - - if (flags & TCP_SYN) { - optflags = TF_SEG_OPTS_MSS; - } -#if LWIP_TCP_TIMESTAMPS - if ((pcb->flags & TF_TIMESTAMP)) { - optflags |= TF_SEG_OPTS_TS; - } -#endif /* LWIP_TCP_TIMESTAMPS */ - optlen = LWIP_TCP_OPT_LENGTH(optflags); - - /* tcp_enqueue_flags is always called with either SYN or FIN in flags. - * We need one available snd_buf byte to do that. - * This means we can't send FIN while snd_buf==0. A better fix would be to - * not include SYN and FIN sequence numbers in the snd_buf count. */ - if (pcb->snd_buf == 0) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n")); - TCP_STATS_INC(tcp.memerr); - return ERR_MEM; - } - - /* Allocate pbuf with room for TCP header + options */ - if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { - pcb->flags |= TF_NAGLEMEMERR; - TCP_STATS_INC(tcp.memerr); - return ERR_MEM; - } - LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen", - (p->len >= optlen)); - - /* Allocate memory for tcp_seg, and fill in fields. */ - if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) { - pcb->flags |= TF_NAGLEMEMERR; - TCP_STATS_INC(tcp.memerr); - return ERR_MEM; - } - LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0); - LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0); - - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, - ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", - ntohl(seg->tcphdr->seqno), - ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), - (u16_t)flags)); - - /* Now append seg to pcb->unsent queue */ - if (pcb->unsent == NULL) { - pcb->unsent = seg; - } else { - struct tcp_seg *useg; - for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); - useg->next = seg; - } -#if TCP_OVERSIZE - /* The new unsent tail has no space */ - pcb->unsent_oversize = 0; -#endif /* TCP_OVERSIZE */ - - /* SYN and FIN bump the sequence number */ - if ((flags & TCP_SYN) || (flags & TCP_FIN)) { - pcb->snd_lbb++; - /* optlen does not influence snd_buf */ - pcb->snd_buf--; - } - if (flags & TCP_FIN) { - pcb->flags |= TF_FIN; - } - - /* update number of segments on the queues */ - pcb->snd_queuelen += pbuf_clen(seg->p); - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_enqueue_flags: invalid queue length", - pcb->unacked != NULL || pcb->unsent != NULL); - } - - return ERR_OK; -} - - -#if LWIP_TCP_TIMESTAMPS -/* Build a timestamp option (12 bytes long) at the specified options pointer) - * - * @param pcb tcp_pcb - * @param opts option pointer where to store the timestamp option - */ -static void ICACHE_FLASH_ATTR -tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts) -{ - /* Pad with two NOP options to make everything nicely aligned */ - opts[0] = PP_HTONL(0x0101080A); - opts[1] = htonl(sys_now()); - opts[2] = htonl(pcb->ts_recent); -} -#endif - -/** Send an ACK without data. - * - * @param pcb Protocol control block for the TCP connection to send the ACK - */ -err_t -tcp_send_empty_ack(struct tcp_pcb *pcb) -{ - struct pbuf *p; - struct tcp_hdr *tcphdr; - u8_t optlen = 0; - -#if LWIP_TCP_TIMESTAMPS - if (pcb->flags & TF_TIMESTAMP) { - optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); - } -#endif - - p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt)); - if (p == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); - return ERR_BUF; - } - tcphdr = (struct tcp_hdr *)p->payload; - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, - ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); - /* remove ACK flags from the PCB, as we send an empty ACK now */ - pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); - - /* NB. MSS option is only sent on SYNs, so ignore it here */ -#if LWIP_TCP_TIMESTAMPS - pcb->ts_lastacksent = pcb->rcv_nxt; - - if (pcb->flags & TF_TIMESTAMP) { - tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1)); - } -#endif - -#if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip), - IP_PROTO_TCP, p->tot_len); -#endif -#if LWIP_NETIF_HWADDRHINT - ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, - IP_PROTO_TCP, &(pcb->addr_hint)); -#else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, - IP_PROTO_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ - pbuf_free(p); - - return ERR_OK; -} - -/** - * Find out what we can send and send it - *���Ϳ��ƿ黺����еı��Ķ� - * @param pcb Protocol control block for the TCP connection to send data - * @return ERR_OK if data has been sent or nothing to send - * another err_t on error - */ -err_t ICACHE_FLASH_ATTR -tcp_output(struct tcp_pcb *pcb) -{ - struct tcp_seg *seg, *useg; - u32_t wnd, snd_nxt; -#if TCP_CWND_DEBUG - s16_t i = 0; -#endif /* TCP_CWND_DEBUG */ - /* First, check if we are invoked by the TCP input processing - code. If so, we do not output anything. Instead, we rely on the - input processing code to call us when input processing is done - with. �����ƿ鵱ǰ������ݱ����?ֱ�ӷ���*/ - if (tcp_input_pcb == pcb) { - return ERR_OK; - } - - wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);//�ӷ��ʹ��ں������ȡС�ߵõ���Ч���ʹ��� - - seg = pcb->unsent; - - /* If the TF_ACK_NOW flag is set and no data will be sent (either - * because the ->unsent queue is empty or because the window does - * not allow it), construct an empty ACK segment and send it. - * - * If data is to be sent, we will just piggyback the ACK (see below). - */ - if (pcb->flags & TF_ACK_NOW && - (seg == NULL || - ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { - return tcp_send_empty_ack(pcb);//����ֻ��ACK�ı��Ķ� - } - - /* useg should point to last segment on unacked queue */ - useg = pcb->unacked; - if (useg != NULL) { - for (; useg->next != NULL; useg = useg->next);//�õ�β�� - } - -#if TCP_OUTPUT_DEBUG - if (seg == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", - (void*)pcb->unsent)); - } -#endif /* TCP_OUTPUT_DEBUG */ -#if TCP_CWND_DEBUG - if (seg == NULL) { - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F - ", cwnd %"U16_F", wnd %"U32_F - ", seg == NULL, ack %"U32_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack)); - } else { - LWIP_DEBUGF(TCP_CWND_DEBUG, - ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F - ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, - ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len, - ntohl(seg->tcphdr->seqno), pcb->lastack)); - } -#endif /* TCP_CWND_DEBUG */ - /* data available and window allows it to be sent? - *��ǰ��Ч�������?�ķ��ͣ�ѭ�����ͱ��ģ�ֱ�������*/ - while (seg != NULL && - ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { - LWIP_ASSERT("RST not expected here!", - (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); - /* Stop sending if the nagle algorithm would prevent it - * Don't stop: - * - if tcp_write had a memory error before (prevent delayed ACK timeout) or - * - if FIN was already enqueued for this PCB (SYN is always alone in a segment - - * either seg->next != NULL or pcb->unacked == NULL; - * RST is no sent using tcp_write/tcp_output. - */ - if((tcp_do_output_nagle(pcb) == 0) && - ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){ - break; - } -#if TCP_CWND_DEBUG - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, - ntohl(seg->tcphdr->seqno) + seg->len - - pcb->lastack, - ntohl(seg->tcphdr->seqno), pcb->lastack, i)); - ++i; -#endif /* TCP_CWND_DEBUG */ - - pcb->unsent = seg->next; - - if (pcb->state != SYN_SENT) { - TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);//��д�ײ�ACK��־ - pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);//����־λ - } - - tcp_output_segment(seg, pcb);//���ú����ͱ��Ķ� - - snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);//����snd_nxt - if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { - pcb->snd_nxt = snd_nxt;//����Ҫ���͵���ݱ�� - } - /* put segment on unacknowledged list if length > 0 - */ - if (TCP_TCPLEN(seg) > 0) { - seg->next = NULL; - /* unacked list is empty? ֱ�ӹҽ�*/ - if (pcb->unacked == NULL) { - pcb->unacked = seg; - useg = seg; - /* unacked list is not empty?����ǰ���İ�˳����֯�ڶ����� */ - } else { - /* In the case of fast retransmit, the packet should not go to the tail - * of the unacked queue, but rather somewhere before it. We need to check for - * this case. -STJ Jul 27, 2004 */ //���ǰ���ĵ����кŵ��ڶ���β���������кţ� - //�Ӷ����ײ���ʼ - if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) { - /* add segment to before tail of unacked list, keeping the list sorted */ - struct tcp_seg **cur_seg = &(pcb->unacked); - while (*cur_seg && - TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { - cur_seg = &((*cur_seg)->next ); - } - seg->next = (*cur_seg); - (*cur_seg) = seg; - } else {//���������ߣ������δȷ�϶���ĩβ - /* add segment to tail of unacked list */ - useg->next = seg; - useg = useg->next; - } - } - /* do not queue empty segments on the unacked list */ - } else {//���Ķγ���Ϊ0��ֱ��ɾ�������ش� - tcp_seg_free(seg); - } - seg = pcb->unsent;//������һ�����Ķ� - } -#if TCP_OVERSIZE - if (pcb->unsent == NULL) { - /* last unsent has been removed, reset unsent_oversize */ - pcb->unsent_oversize = 0; - } -#endif /* TCP_OVERSIZE */ - -//���ʹ��������±��IJ��ܷ��ͣ��������㴰��̽�⡣ - if (seg != NULL && pcb->persist_backoff == 0 && - ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) { - /* prepare for persist timer */ - pcb->persist_cnt = 0; - pcb->persist_backoff = 1; - } - - pcb->flags &= ~TF_NAGLEMEMERR;//���ڴ�����־ - return ERR_OK; -} - -/** - * Called by tcp_output() to actually send a TCP segment over IP. - * - * @param seg the tcp_seg to send - * @param pcb the tcp_pcb for the TCP connection used to send the segment - */ - -static void -tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) -{ - u16_t len; - struct netif *netif; - u32_t *opts; - /** @bug Exclude retransmitted segments from this count. */ - snmp_inc_tcpoutsegs(); - - /* The TCP header has already been constructed, but the ackno and - wnd fields remain. */ - seg->tcphdr->ackno = htonl(pcb->rcv_nxt); - - /* advertise our receive window size in this TCP segment */ - seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd); - - pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; - - /* Add any requested options. NB MSS option is only set on SYN - packets, so ignore it here */ - LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0); - opts = (u32_t *)(void *)(seg->tcphdr + 1); - if (seg->flags & TF_SEG_OPTS_MSS) { - TCP_BUILD_MSS_OPTION(*opts); - opts += 1; - } -#if LWIP_TCP_TIMESTAMPS - pcb->ts_lastacksent = pcb->rcv_nxt; - - if (seg->flags & TF_SEG_OPTS_TS) { - tcp_build_timestamp_option(pcb, opts); - opts += 3; - } -#endif - - /* Set retransmission timer running if it is not currently enabled - This must be set before checking the route. modify by ives at 2014.4.24*/ - if (pcb->rtime == -1) { - pcb->rtime = 0; - } - - /* If we don't have a local IP address, we get one by - calling ip_route(). */ - if (ip_addr_isany(&(pcb->local_ip))) { - netif = ip_route(&(pcb->remote_ip)); - if (netif == NULL) { - return; - } - ip_addr_copy(pcb->local_ip, netif->ip_addr); - } - - if (pcb->rttest == 0) { - pcb->rttest = tcp_ticks; - pcb->rtseq = ntohl(seg->tcphdr->seqno); - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq)); - } - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n", - htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) + - seg->len)); - - len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload); - - seg->p->len -= len; - seg->p->tot_len -= len; - - seg->p->payload = seg->tcphdr; - - seg->tcphdr->chksum = 0; -#if CHECKSUM_GEN_TCP -#if TCP_CHECKSUM_ON_COPY - { - u32_t acc; -#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK - u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip), - &(pcb->remote_ip), - IP_PROTO_TCP, seg->p->tot_len); -#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ - if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) { - LWIP_ASSERT("data included but not checksummed", - seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4)); - } - - /* rebuild TCP header checksum (TCP header changes for retransmissions!) */ - acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip), - &(pcb->remote_ip), - IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4); - /* add payload checksum */ - if (seg->chksum_swapped) { - seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); - seg->chksum_swapped = 0; - } - acc += (u16_t)~(seg->chksum); - seg->tcphdr->chksum = FOLD_U32T(acc); -#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK - if (chksum_slow != seg->tcphdr->chksum) { - LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING, - ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n", - seg->tcphdr->chksum, chksum_slow)); - seg->tcphdr->chksum = chksum_slow; - } -#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ - } -#else /* TCP_CHECKSUM_ON_COPY */ - seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip), - &(pcb->remote_ip), - IP_PROTO_TCP, seg->p->tot_len); -#endif /* TCP_CHECKSUM_ON_COPY */ -#endif /* CHECKSUM_GEN_TCP */ - TCP_STATS_INC(tcp.xmit); - -#if LWIP_NETIF_HWADDRHINT - ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, - IP_PROTO_TCP, &(pcb->addr_hint)); -#else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, - IP_PROTO_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ -} - -/** - * Send a TCP RESET packet (empty segment with RST flag set) either to - * abort a connection or to show that there is no matching local connection - * for a received segment. - * - * Called by tcp_abort() (to abort a local connection), tcp_input() (if no - * matching local pcb was found), tcp_listen_input() (if incoming segment - * has ACK flag set) and tcp_process() (received segment in the wrong state) - * - * Since a RST segment is in most cases not sent for an active connection, - * tcp_rst() has a number of arguments that are taken from a tcp_pcb for - * most other segment output functions. - * - * @param seqno the sequence number to use for the outgoing segment - * @param ackno the acknowledge number to use for the outgoing segment - * @param local_ip the local IP address to send the segment from - * @param remote_ip the remote IP address to send the segment to - * @param local_port the local TCP port to send the segment from - * @param remote_port the remote TCP port to send the segment to - */ -void -tcp_rst(u32_t seqno, u32_t ackno, - ip_addr_t *local_ip, ip_addr_t *remote_ip, - u16_t local_port, u16_t remote_port) -{ - struct pbuf *p; - struct tcp_hdr *tcphdr; - p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); - if (p == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); - return; - } - LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", - (p->len >= sizeof(struct tcp_hdr))); - - tcphdr = (struct tcp_hdr *)p->payload; - tcphdr->src = htons(local_port); - tcphdr->dest = htons(remote_port); - tcphdr->seqno = htonl(seqno); - tcphdr->ackno = htonl(ackno); - TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK); - tcphdr->wnd = PP_HTONS(TCP_WND); - tcphdr->chksum = 0; - tcphdr->urgp = 0; - -#if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip, - IP_PROTO_TCP, p->tot_len); -#endif - TCP_STATS_INC(tcp.xmit); - snmp_inc_tcpoutrsts(); - /* Send output with hardcoded TTL since we have no access to the pcb */ - ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP); - pbuf_free(p); - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); -} - -/** - * Requeue all unacked segments for retransmission - * - * Called by tcp_slowtmr() for slow retransmission. - * - * @param pcb the tcp_pcb for which to re-enqueue all unacked segments - */ -void -tcp_rexmit_rto(struct tcp_pcb *pcb) -{ - struct tcp_seg *seg; - struct tcp_seg *t0_head = NULL, *t0_tail = NULL; /* keep in unacked */ - struct tcp_seg *t1_head = NULL, *t1_tail = NULL; /* link to unsent */ - bool t0_1st = true, t1_1st = true; - - if (pcb->unacked == NULL) { - return; - } - -#if 1 /* by Snake: resolve the bug of pbuf reuse */ - seg = pcb->unacked; - while (seg != NULL) { - if (seg->p->eb) { - if (t0_1st) { - t0_head = t0_tail = seg; - t0_1st = false; - } else { - t0_tail->next = seg; - t0_tail = seg; - } - seg = seg->next; - t0_tail->next = NULL; - } else { - if (t1_1st) { - t1_head = t1_tail = seg; - t1_1st = false; - } else { - t1_tail->next = seg; - t1_tail = seg; - } - seg = seg->next; - t1_tail->next = NULL; - } - } - if (t1_head && t1_tail) { - t1_tail->next = pcb->unsent; - pcb->unsent = t1_head; - } - pcb->unacked = t0_head; - -#else - - /* Move all unacked segments to the head of the unsent queue */ - for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); - /* concatenate unsent queue after unacked queue */ - seg->next = pcb->unsent; - /* unsent queue is the concatenated queue (of unacked, unsent) */ - pcb->unsent = pcb->unacked; - /* unacked queue is now empty */ - pcb->unacked = NULL; -#endif - - /* increment number of retransmissions */ - ++pcb->nrtx; - - /* Don't take any RTT measurements after retransmitting. */ - pcb->rttest = 0; - - /* Do the actual retransmission */ - tcp_output(pcb); -} - -/** - * Requeue the first unacked segment for retransmission - * - * Called by tcp_receive() for fast retramsmit. - * - * @param pcb the tcp_pcb for which to retransmit the first unacked segment - */ -void -tcp_rexmit(struct tcp_pcb *pcb) -{ - struct tcp_seg *seg; - struct tcp_seg **cur_seg; - - if (pcb->unacked == NULL) { - return; - } - - /* Move the first unacked segment to the unsent queue */ - /* Keep the unsent queue sorted. */ - seg = pcb->unacked; - pcb->unacked = seg->next; - - cur_seg = &(pcb->unsent); - while (*cur_seg && - TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { - cur_seg = &((*cur_seg)->next ); - } - seg->next = *cur_seg; - *cur_seg = seg; - - ++pcb->nrtx; - - /* Don't take any rtt measurements after retransmitting. */ - pcb->rttest = 0; - - /* Do the actual retransmission. */ - snmp_inc_tcpretranssegs(); - /* No need to call tcp_output: we are always called from tcp_input() - and thus tcp_output directly returns. */ -} - - -/** - * Handle retransmission after three dupacks received - * - * @param pcb the tcp_pcb for which to retransmit the first unacked segment - */ -void -tcp_rexmit_fast(struct tcp_pcb *pcb) -{ - if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) { - /* This is fast retransmit. Retransmit the first unacked segment. */ - LWIP_DEBUGF(TCP_FR_DEBUG, - ("tcp_receive: dupacks %"U16_F" (%"U32_F - "), fast retransmit %"U32_F"\n", - (u16_t)pcb->dupacks, pcb->lastack, - ntohl(pcb->unacked->tcphdr->seqno))); - tcp_rexmit(pcb); - - /* Set ssthresh to half of the minimum of the current - * cwnd and the advertised window */ - if (pcb->cwnd > pcb->snd_wnd) { - pcb->ssthresh = pcb->snd_wnd / 2; - } else { - pcb->ssthresh = pcb->cwnd / 2; - } - - /* The minimum value for ssthresh should be 2 MSS */ - if (pcb->ssthresh < 2*pcb->mss) { - LWIP_DEBUGF(TCP_FR_DEBUG, - ("tcp_receive: The minimum value for ssthresh %"U16_F - " should be min 2 mss %"U16_F"...\n", - pcb->ssthresh, 2*pcb->mss)); - pcb->ssthresh = 2*pcb->mss; - } - - pcb->cwnd = pcb->ssthresh + 3 * pcb->mss; - pcb->flags |= TF_INFR; - } -} - - -/** - * Send keepalive packets to keep a connection active although - * no data is sent over it. - * - * Called by tcp_slowtmr() - * - * @param pcb the tcp_pcb for which to send a keepalive packet - */ -void -tcp_keepalive(struct tcp_pcb *pcb) -{ - struct pbuf *p; - struct tcp_hdr *tcphdr; - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), - ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", - tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); - - p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1)); - if(p == NULL) { - LWIP_DEBUGF(TCP_DEBUG, - ("tcp_keepalive: could not allocate memory for pbuf\n")); - return; - } - tcphdr = (struct tcp_hdr *)p->payload; - -#if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, - IP_PROTO_TCP, p->tot_len); -#endif - TCP_STATS_INC(tcp.xmit); - - /* Send output to IP */ -#if LWIP_NETIF_HWADDRHINT - ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, - &(pcb->addr_hint)); -#else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ - - pbuf_free(p); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n", - pcb->snd_nxt - 1, pcb->rcv_nxt)); -} - - -/** - * Send persist timer zero-window probes to keep a connection active - * when a window update is lost. - * - * Called by tcp_slowtmr() - * - * @param pcb the tcp_pcb for which to send a zero-window probe packet - */ -void -tcp_zero_window_probe(struct tcp_pcb *pcb) -{ - struct pbuf *p; - struct tcp_hdr *tcphdr; - struct tcp_seg *seg; - u16_t offset = 0; - u16_t len; - u8_t is_fin; - - LWIP_DEBUGF(TCP_DEBUG, - ("tcp_zero_window_probe: sending ZERO WINDOW probe to %" - U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), - ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); - - LWIP_DEBUGF(TCP_DEBUG, - ("tcp_zero_window_probe: tcp_ticks %"U32_F - " pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", - tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); - - seg = pcb->unacked; - - if(seg == NULL) { - seg = pcb->unsent; - } else { - struct ip_hdr *iphdr = NULL; - iphdr = (struct ip_hdr *)((char*)seg->p->payload + SIZEOF_ETH_HDR); - offset = IPH_HL(iphdr)*4; - offset += SIZEOF_ETH_HDR; - } - if(seg == NULL) { - return; - } - - is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0); - /* we want to send one seqno: either FIN or data (no options) */ - len = is_fin ? 0 : 1; - - p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno); - if(p == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n")); - return; - } - tcphdr = (struct tcp_hdr *)p->payload; - - if (is_fin) { - /* FIN segment, no data */ - TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN); - } else { - /* Data segment, copy in one byte from the head of the unacked queue */ - struct tcp_hdr *thdr = (struct tcp_hdr *)seg->p->payload; - char *d = ((char *)p->payload + TCP_HLEN); - if (pcb->unacked == NULL) - pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4); - else { - thdr = (struct tcp_hdr *)((char*)seg->p->payload + offset); - pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4 + offset); - } - } - -#if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, - IP_PROTO_TCP, p->tot_len); -#endif - TCP_STATS_INC(tcp.xmit); - - /* Send output to IP */ -#if LWIP_NETIF_HWADDRHINT - ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, - &(pcb->addr_hint)); -#else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ - - pbuf_free(p); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F - " ackno %"U32_F".\n", - pcb->snd_nxt - 1, pcb->rcv_nxt)); -} -#endif /* LWIP_TCP */ diff --git a/tools/sdk/lwip/src/core/timers.c b/tools/sdk/lwip/src/core/timers.c deleted file mode 100644 index e682bd2d7..000000000 --- a/tools/sdk/lwip/src/core/timers.c +++ /dev/null @@ -1,513 +0,0 @@ -/** - * @file - * Stack-internal timers implementation. - * This file includes timer callbacks for stack-internal timers as well as - * functions to set up or stop timers and check for expired timers. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * Simon Goldschmidt - * - */ - -#include "lwip/opt.h" - -#include "lwip/timers.h" -#include "lwip/tcp_impl.h" - -#if LWIP_TIMERS - -#include "lwip/def.h" -#include "lwip/memp.h" -#include "lwip/tcpip.h" - -#include "lwip/ip_frag.h" -#include "netif/etharp.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" -#include "lwip/igmp.h" -#include "lwip/dns.h" - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -/** The one and only timeout list */ -static struct sys_timeo *next_timeout = NULL; -#if NO_SYS -static u32_t timeouts_last_time; -#endif /* NO_SYS */ - -#if LWIP_TCP -/** global variable that shows if the tcp timer is currently scheduled or not */ -static int tcpip_tcp_timer_active; - -/** - * Timer callback function that calls tcp_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void ICACHE_FLASH_ATTR -tcpip_tcp_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - - /* call TCP timer handler */ - tcp_tmr(); - /* timer still needed? */ - if (tcp_active_pcbs || tcp_tw_pcbs) { - /* restart timer */ - sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); - } else { - /* disable timer */ - tcpip_tcp_timer_active = 0; - } -} - -/** - * Called from TCP_REG when registering a new PCB: - * the reason is to have the TCP timer only running when - * there are active (or time-wait) PCBs. - */ -void -tcp_timer_needed(void) -{ - /* timer is off but needed again? */ - if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { - /* enable and start timer */ - tcpip_tcp_timer_active = 1; - sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); - } -} - -/** - * Timer callback function that calls tcp_tmr() and reschedules itself. - * - * @param arg unused argument - */ - -static void ICACHE_FLASH_ATTR -tcp_timer_coarse(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: tcp_tmr()\n")); - tcp_tmr(); - sys_timeout(TCP_TMR_INTERVAL, tcp_timer_coarse, NULL); -} - -#endif /* LWIP_TCP */ - -#if IP_REASSEMBLY -/** - * Timer callback function that calls ip_reass_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void ICACHE_FLASH_ATTR -ip_reass_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n")); - ip_reass_tmr(); - sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); -} -#endif /* IP_REASSEMBLY */ - -#if LWIP_ARP -/** - * Timer callback function that calls etharp_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void ICACHE_FLASH_ATTR -arp_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n")); - etharp_tmr(); - sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); -} -#endif /* LWIP_ARP */ - -#if LWIP_DHCP -/** - * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself. - * - * @param arg unused argument - */ -extern void dhcps_coarse_tmr(void); -static void -dhcp_timer_coarse(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n")); - dhcp_coarse_tmr(); - dhcps_coarse_tmr(); - sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); -} - -/** - * Timer callback function that calls dhcp_fine_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -dhcp_timer_fine(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n")); - dhcp_fine_tmr(); - sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); -} -#endif /* LWIP_DHCP */ - -#if LWIP_AUTOIP -/** - * Timer callback function that calls autoip_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -autoip_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n")); - autoip_tmr(); - sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); -} -#endif /* LWIP_AUTOIP */ - -#if LWIP_IGMP -/** - * Timer callback function that calls igmp_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -igmp_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n")); - igmp_tmr(); - sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); -} -#endif /* LWIP_IGMP */ - -#if LWIP_DNS -/** - * Timer callback function that calls dns_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -dns_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n")); - dns_tmr(); - sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); -} -#endif /* LWIP_DNS */ - -/** Initialize this module */ -void sys_timeouts_init(void) -{ -#if IP_REASSEMBLY - sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); -#endif /* IP_REASSEMBLY */ -#if LWIP_ARP - sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); -#endif /* LWIP_ARP */ -#if LWIP_DHCP - DHCP_MAXRTX = 0; - sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); - sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); -#endif /* LWIP_DHCP */ -#if LWIP_AUTOIP - sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); -#endif /* LWIP_AUTOIP */ -#if LWIP_IGMP - sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); -#endif /* LWIP_IGMP */ -#if LWIP_DNS - sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); -#endif /* LWIP_DNS */ - -#if LWIP_TCP - sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); -// sys_timeout(TCP_TMR_INTERVAL, tcp_timer_coarse, NULL); -#endif - -#if NO_SYS - /* Initialise timestamp for sys_check_timeouts */ - timeouts_last_time = NOW(); -#endif -} - -/** - * Create a one-shot timer (aka timeout). Timeouts are processed in the - * following cases: - * - while waiting for a message using sys_timeouts_mbox_fetch() - * - by calling sys_check_timeouts() (NO_SYS==1 only) - * - * @param msecs time in milliseconds after that the timer should expire - * @param handler callback function to call when msecs have elapsed - * @param arg argument to pass to the callback function - */ -#if LWIP_DEBUG_TIMERNAMES -void -sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name) -#else /* LWIP_DEBUG_TIMERNAMES */ -void -sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) -#endif /* LWIP_DEBUG_TIMERNAMES */ -{ - struct sys_timeo *timeout, *t; - - timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); - if (timeout == NULL) { - LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); - return; - } - timeout->next = NULL; - timeout->h = handler; - timeout->arg = arg; - timeout->time = msecs; -#if LWIP_DEBUG_TIMERNAMES - timeout->handler_name = handler_name; - LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n", - (void *)timeout, msecs, handler_name, (void *)arg)); -#endif /* LWIP_DEBUG_TIMERNAMES */ - - if (next_timeout == NULL) { - next_timeout = timeout; - return; - } - - if (next_timeout->time > msecs) { - next_timeout->time -= msecs; - timeout->next = next_timeout; - next_timeout = timeout; - } else { - for(t = next_timeout; t != NULL; t = t->next) { - timeout->time -= t->time; - if (t->next == NULL || t->next->time > timeout->time) { - if (t->next != NULL) { - t->next->time -= timeout->time; - } - timeout->next = t->next; - t->next = timeout; - break; - } - } - } -} - -/** - * Go through timeout list (for this task only) and remove the first matching - * entry, even though the timeout has not triggered yet. - * - * @note This function only works as expected if there is only one timeout - * calling 'handler' in the list of timeouts. - * - * @param handler callback function that would be called by the timeout - * @param arg callback argument that would be passed to handler -*/ -void -sys_untimeout(sys_timeout_handler handler, void *arg) -{ - struct sys_timeo *prev_t, *t; - - if (next_timeout == NULL) { - return; - } - - for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { - if ((t->h == handler) && (t->arg == arg)) { - /* We have a match */ - /* Unlink from previous in list */ - if (prev_t == NULL) { - next_timeout = t->next; - } else { - prev_t->next = t->next; - } - /* If not the last one, add time of this one back to next */ - if (t->next != NULL) { - t->next->time += t->time; - } - memp_free(MEMP_SYS_TIMEOUT, t); - return; - } - } - return; -} - -#if NO_SYS -extern uint8 timer2_ms_flag; -/** Handle timeouts for NO_SYS==1 (i.e. without using - * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout - * handler functions when timeouts expire. - * - * Must be called periodically from your main loop. - */ -void -sys_check_timeouts(void) -{ - struct sys_timeo *tmptimeout; - u32_t diff; - sys_timeout_handler handler; - void *arg; - int had_one; - u32_t now; - - now = NOW(); - if (next_timeout) { - /* this cares for wraparounds */ - if (timer2_ms_flag == 0) { - diff = LWIP_U32_DIFF(now, timeouts_last_time)/((APB_CLK_FREQ>>4)/1000); - } else { - diff = LWIP_U32_DIFF(now, timeouts_last_time)/((APB_CLK_FREQ>>8)/1000); - } - do - { - had_one = 0; - tmptimeout = next_timeout; - if (tmptimeout->time <= diff) { - /* timeout has expired */ - had_one = 1; - timeouts_last_time = now; - diff -= tmptimeout->time; - next_timeout = tmptimeout->next; - handler = tmptimeout->h; - arg = tmptimeout->arg; -#if LWIP_DEBUG_TIMERNAMES - if (handler != NULL) { - LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n", - tmptimeout->handler_name, arg)); - } -#endif /* LWIP_DEBUG_TIMERNAMES */ - memp_free(MEMP_SYS_TIMEOUT, tmptimeout); - if (handler != NULL) { - handler(arg); - } - } - /* repeat until all expired timers have been called */ - }while(had_one); - } -} - -/** Set back the timestamp of the last call to sys_check_timeouts() - * This is necessary if sys_check_timeouts() hasn't been called for a long - * time (e.g. while saving energy) to prevent all timer functions of that - * period being called. - */ -void -sys_restart_timeouts(void) -{ - timeouts_last_time = NOW(); -} - -#else /* NO_SYS */ - -/** - * Wait (forever) for a message to arrive in an mbox. - * While waiting, timeouts are processed. - * - * @param mbox the mbox to fetch the message from - * @param msg the place to store the message - */ -void -sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) -{ - u32_t time_needed; - struct sys_timeo *tmptimeout; - sys_timeout_handler handler; - void *arg; - - again: - if (!next_timeout) { - time_needed = sys_arch_mbox_fetch(mbox, msg, 0); - } else { - if (next_timeout->time > 0) { - time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time); - } else { - time_needed = SYS_ARCH_TIMEOUT; - } - - if (time_needed == SYS_ARCH_TIMEOUT) { - /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message - could be fetched. We should now call the timeout handler and - deallocate the memory allocated for the timeout. */ - tmptimeout = next_timeout; - next_timeout = tmptimeout->next; - handler = tmptimeout->h; - arg = tmptimeout->arg; -#if LWIP_DEBUG_TIMERNAMES - if (handler != NULL) { - LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n", - tmptimeout->handler_name, arg)); - } -#endif /* LWIP_DEBUG_TIMERNAMES */ - memp_free(MEMP_SYS_TIMEOUT, tmptimeout); - if (handler != NULL) { - /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the - timeout handler function. */ - LOCK_TCPIP_CORE(); - handler(arg); - UNLOCK_TCPIP_CORE(); - } - LWIP_TCPIP_THREAD_ALIVE(); - - /* We try again to fetch a message from the mbox. */ - goto again; - } else { - /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout - occured. The time variable is set to the number of - milliseconds we waited for the message. */ - if (time_needed < next_timeout->time) { - next_timeout->time -= time_needed; - } else { - next_timeout->time = 0; - } - } - } -} - -#endif /* NO_SYS */ - -#else /* LWIP_TIMERS */ -/* Satisfy the TCP code which calls this function */ -void -tcp_timer_needed(void) -{ -} -#endif /* LWIP_TIMERS */ diff --git a/tools/sdk/lwip/src/core/udp.c b/tools/sdk/lwip/src/core/udp.c deleted file mode 100644 index 42539d6d7..000000000 --- a/tools/sdk/lwip/src/core/udp.c +++ /dev/null @@ -1,989 +0,0 @@ -/** - * @file - * User Datagram Protocol module - * - */ - -/* - * 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 - * - */ - - -/* udp.c - * - * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828). - * - */ - -/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'! - */ - -#include "lwip/opt.h" - -#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/udp.h" -#include "lwip/def.h" -#include "lwip/memp.h" -#include "lwip/inet_chksum.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/icmp.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "arch/perf.h" -#include "lwip/dhcp.h" - -#include - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -/* The list of UDP PCBs */ -/* exported in udp.h (was static) */ -struct udp_pcb *udp_pcbs; - -/** - * Process an incoming UDP datagram. - * - * Given an incoming UDP datagram (as a chain of pbufs) this function - * finds a corresponding UDP PCB and hands over the pbuf to the pcbs - * recv function. If no pcb is found or the datagram is incorrect, the - * pbuf is freed. - * - * @param p pbuf to be demultiplexed to a UDP PCB. - * @param inp network interface on which the datagram was received. - * - */ -void ICACHE_FLASH_ATTR -udp_input(struct pbuf *p, struct netif *inp) -{ - struct udp_hdr *udphdr; - struct udp_pcb *pcb, *prev; - struct udp_pcb *uncon_pcb; - struct ip_hdr *iphdr; - u16_t src, dest; - u8_t local_match; - u8_t broadcast; - - PERF_START; - - UDP_STATS_INC(udp.recv); - - iphdr = (struct ip_hdr *)p->payload; - - /* Check minimum length (IP header + UDP header) - * and move payload pointer to UDP header */ - if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) { - /* drop short packets */ - LWIP_DEBUGF(UDP_DEBUG, - ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); - UDP_STATS_INC(udp.lenerr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; - } - - udphdr = (struct udp_hdr *)p->payload; - - /* is broadcast packet ? */ - broadcast = ip_addr_isbroadcast(¤t_iphdr_dest, inp); - - LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); - - /* convert src and dest ports to host byte order */ - src = ntohs(udphdr->src); - dest = ntohs(udphdr->dest); - - udp_debug_print(udphdr); - - /* print the UDP source and destination */ - LWIP_DEBUGF(UDP_DEBUG, - ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- " - "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", - ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest), - ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest), - ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src), - ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src))); - -#if LWIP_DHCP - pcb = NULL; - /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by - the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */ - if (dest == DHCP_CLIENT_PORT) { - /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */ - if (src == DHCP_SERVER_PORT) { - if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) { - /* accept the packe if - (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY! - - inp->dhcp->pcb->remote == ANY or iphdr->src */ - if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) || - ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), ¤t_iphdr_src))) { - pcb = inp->dhcp->pcb; - } - } - } - } else if (dest == DHCP_SERVER_PORT) { - if (src == DHCP_CLIENT_PORT) { - if ( inp->dhcps_pcb != NULL ) { - if ((ip_addr_isany(&inp->dhcps_pcb->local_ip) || - ip_addr_cmp(&(inp->dhcps_pcb->local_ip), ¤t_iphdr_dest))) { - pcb = inp->dhcps_pcb; - } - } - } - } else -#endif /* LWIP_DHCP */ - { - prev = NULL; - local_match = 0; - uncon_pcb = NULL; - /* Iterate through the UDP pcb list for a matching pcb. - * 'Perfect match' pcbs (connected to the remote port & ip address) are - * preferred. If no perfect match is found, the first unconnected pcb that - * matches the local port and ip address gets the datagram. */ - for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { - local_match = 0; - /* print the PCB local and remote address */ - LWIP_DEBUGF(UDP_DEBUG, - ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- " - "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", - ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), - ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port, - ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), - ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port)); - - /* compare PCB local addr+port to UDP destination addr+port */ - if ((pcb->local_port == dest) && - ((!broadcast && ip_addr_isany(&pcb->local_ip)) || - ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest) || -#if LWIP_IGMP - ip_addr_ismulticast(¤t_iphdr_dest) || -#endif /* LWIP_IGMP */ -#if IP_SOF_BROADCAST_RECV - (broadcast && (pcb->so_options & SOF_BROADCAST)))) { -#else /* IP_SOF_BROADCAST_RECV */ - (broadcast))) { -#endif /* IP_SOF_BROADCAST_RECV */ - local_match = 1; - if ((uncon_pcb == NULL) && - ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { - /* the first unconnected matching PCB */ - uncon_pcb = pcb; - } - } - /* compare PCB remote addr+port to UDP source addr+port */ - if ((local_match != 0) && - (pcb->remote_port == src) && - (ip_addr_isany(&pcb->remote_ip) || - ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src))) { - /* the first fully matching PCB */ - if (prev != NULL) { - /* move the pcb to the front of udp_pcbs so that is - found faster next time */ - prev->next = pcb->next; - pcb->next = udp_pcbs; - udp_pcbs = pcb; - } else { - UDP_STATS_INC(udp.cachehit); - } - break; - } - prev = pcb; - } - /* no fully matching pcb found? then look for an unconnected pcb */ - if (pcb == NULL) { - pcb = uncon_pcb; - } - } - - /* Check checksum if this is a match or if it was directed at us. */ - if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, ¤t_iphdr_dest)) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); -#if LWIP_UDPLITE - if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) { - /* Do the UDP Lite checksum */ -#if CHECKSUM_CHECK_UDP - u16_t chklen = ntohs(udphdr->len); - if (chklen < sizeof(struct udp_hdr)) { - if (chklen == 0) { - /* For UDP-Lite, checksum length of 0 means checksum - over the complete packet (See RFC 3828 chap. 3.1) */ - chklen = p->tot_len; - } else { - /* At least the UDP-Lite header must be covered by the - checksum! (Again, see RFC 3828 chap. 3.1) */ - UDP_STATS_INC(udp.chkerr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; - } - } - if (inet_chksum_pseudo_partial(p, ¤t_iphdr_src, ¤t_iphdr_dest, - IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("udp_input: UDP Lite datagram discarded due to failing checksum\n")); - UDP_STATS_INC(udp.chkerr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; - } -#endif /* CHECKSUM_CHECK_UDP */ - } else -#endif /* LWIP_UDPLITE */ - { -#if CHECKSUM_CHECK_UDP - if (udphdr->chksum != 0) { - if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), - IP_PROTO_UDP, p->tot_len) != 0) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("udp_input: UDP datagram discarded due to failing checksum\n")); - UDP_STATS_INC(udp.chkerr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; - } - } -#endif /* CHECKSUM_CHECK_UDP */ - } - if(pbuf_header(p, -UDP_HLEN)) { - /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_header failed\n", 0); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; - } - if (pcb != NULL) { - snmp_inc_udpindatagrams(); -#if SO_REUSE && SO_REUSE_RXTOALL - if ((broadcast || ip_addr_ismulticast(¤t_iphdr_dest)) && - ((pcb->so_options & SOF_REUSEADDR) != 0)) { - /* pass broadcast- or multicast packets to all multicast pcbs - if SOF_REUSEADDR is set on the first match */ - struct udp_pcb *mpcb; - u8_t p_header_changed = 0; - for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { - if (mpcb != pcb) { - /* compare PCB local addr+port to UDP destination addr+port */ - if ((mpcb->local_port == dest) && - ((!broadcast && ip_addr_isany(&mpcb->local_ip)) || - ip_addr_cmp(&(mpcb->local_ip), ¤t_iphdr_dest) || -#if LWIP_IGMP - ip_addr_ismulticast(¤t_iphdr_dest) || -#endif /* LWIP_IGMP */ -#if IP_SOF_BROADCAST_RECV - (broadcast && (mpcb->so_options & SOF_BROADCAST)))) { -#else /* IP_SOF_BROADCAST_RECV */ - (broadcast))) { -#endif /* IP_SOF_BROADCAST_RECV */ - /* pass a copy of the packet to all local matches */ - if (mpcb->recv != NULL) { - struct pbuf *q; - /* for that, move payload to IP header again */ - if (p_header_changed == 0) { - pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); - p_header_changed = 1; - } - q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if (q != NULL) { - err_t err = pbuf_copy(q, p); - if (err == ERR_OK) { - /* move payload to UDP data */ - pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); - mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); - } - } - } - } - } - } - if (p_header_changed) { - /* and move payload to UDP data again */ - pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); - } - } -#endif /* SO_REUSE && SO_REUSE_RXTOALL */ - /* callback */ - if (pcb->recv != NULL) { - /* now the recv function is responsible for freeing p */ - pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); - } else { - /* no recv function registered? then we have to free the pbuf! */ - pbuf_free(p); - goto end; - } - } else { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); - -#if LWIP_ICMP - /* No match was found, send ICMP destination port unreachable unless - destination address was broadcast/multicast. */ - if (!broadcast && - !ip_addr_ismulticast(¤t_iphdr_dest)) { - /* move payload pointer back to ip header */ - pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN); - LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr)); - icmp_dest_unreach(p, ICMP_DUR_PORT); - } -#endif /* LWIP_ICMP */ - UDP_STATS_INC(udp.proterr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpnoports(); - pbuf_free(p); - } - } else { - pbuf_free(p); - } -end: - PERF_STOP("udp_input"); -} - -/** - * Send data using UDP. - * - * @param pcb UDP PCB used to send the data. - * @param p chain of pbuf's to be sent. - * - * The datagram will be sent to the current remote_ip & remote_port - * stored in pcb. If the pcb is not bound to a port, it will - * automatically be bound to a random port. - * - * @return lwIP error code. - * - ERR_OK. Successful. No error occured. - * - ERR_MEM. Out of memory. - * - ERR_RTE. Could not find route to destination address. - * - More errors could be returned by lower protocol layers. - * - * @see udp_disconnect() udp_sendto() - */ -err_t ICACHE_FLASH_ATTR -udp_send(struct udp_pcb *pcb, struct pbuf *p) -{ - /* send to the packet using remote ip and port stored in the pcb */ - return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); -} - -#if LWIP_CHECKSUM_ON_COPY -/** Same as udp_send() but with checksum - */ -err_t ICACHE_FLASH_ATTR -udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, - u8_t have_chksum, u16_t chksum) -{ - /* send to the packet using remote ip and port stored in the pcb */ - return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port, - have_chksum, chksum); -} -#endif /* LWIP_CHECKSUM_ON_COPY */ - -/** - * Send data to a specified address using UDP. - * - * @param pcb UDP PCB used to send the data. - * @param p chain of pbuf's to be sent. - * @param dst_ip Destination IP address. - * @param dst_port Destination UDP port. - * - * dst_ip & dst_port are expected to be in the same byte order as in the pcb. - * - * If the PCB already has a remote address association, it will - * be restored after the data is sent. - * - * @return lwIP error code (@see udp_send for possible error codes) - * - * @see udp_disconnect() udp_send() - */ -err_t ICACHE_FLASH_ATTR -udp_sendto(struct udp_pcb *pcb, struct pbuf *p, - ip_addr_t *dst_ip, u16_t dst_port) -{ -#if LWIP_CHECKSUM_ON_COPY - return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0); -} - -/** Same as udp_sendto(), but with checksum */ -err_t ICACHE_FLASH_ATTR -udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, - u16_t dst_port, u8_t have_chksum, u16_t chksum) -{ -#endif /* LWIP_CHECKSUM_ON_COPY */ - struct netif *netif; - - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); - - /* find the outgoing network interface for this packet */ -#if LWIP_IGMP - netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip)); -#else - netif = ip_route(dst_ip); -#endif /* LWIP_IGMP */ - - /* no outgoing network interface could be found? */ - if (netif == NULL) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip))); - UDP_STATS_INC(udp.rterr); - return ERR_RTE; - } -#if LWIP_CHECKSUM_ON_COPY - return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); -#else /* LWIP_CHECKSUM_ON_COPY */ - return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); -#endif /* LWIP_CHECKSUM_ON_COPY */ -} - -/** - * Send data to a specified address using UDP. - * The netif used for sending can be specified. - * - * This function exists mainly for DHCP, to be able to send UDP packets - * on a netif that is still down. - * - * @param pcb UDP PCB used to send the data. - * @param p chain of pbuf's to be sent. - * @param dst_ip Destination IP address. - * @param dst_port Destination UDP port. - * @param netif the netif used for sending. - * - * dst_ip & dst_port are expected to be in the same byte order as in the pcb. - * - * @return lwIP error code (@see udp_send for possible error codes) - * - * @see udp_disconnect() udp_send() - */ -err_t ICACHE_FLASH_ATTR -udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, - ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) -{ -#if LWIP_CHECKSUM_ON_COPY - return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0); -} - -/** Same as udp_sendto_if(), but with checksum */ -err_t ICACHE_FLASH_ATTR -udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, - u16_t dst_port, struct netif *netif, u8_t have_chksum, - u16_t chksum) -{ -#endif /* LWIP_CHECKSUM_ON_COPY */ - struct udp_hdr *udphdr; - ip_addr_t *src_ip; - err_t err; - struct pbuf *q; /* q will be sent down the stack */ - u8_t ttl; - -#if IP_SOF_BROADCAST - /* broadcast filter? */ - if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); - return ERR_VAL; - } -#endif /* IP_SOF_BROADCAST */ - - /* if the PCB is not yet bound to a port, bind it here */ - if (pcb->local_port == 0) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n")); - err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); - if (err != ERR_OK) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); - return err; - } - } - - /* not enough space to add an UDP header to first pbuf in given p chain? */ - if (pbuf_header(p, UDP_HLEN)) { - /* allocate header in a separate new pbuf */ - q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); - /* new header pbuf could not be allocated? */ - if (q == NULL) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n")); - return ERR_MEM; - } - if (p->tot_len != 0) { - /* chain header q in front of given pbuf p (only if p contains data) */ - pbuf_chain(q, p); - } - /* first pbuf q points to header pbuf */ - LWIP_DEBUGF(UDP_DEBUG, - ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); - } else { - /* adding space for header within p succeeded */ - /* first pbuf q equals given pbuf */ - q = p; - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); - } - LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", - (q->len >= sizeof(struct udp_hdr))); - /* q now represents the packet to be sent */ - udphdr = (struct udp_hdr *)q->payload; - udphdr->src = htons(pcb->local_port); - udphdr->dest = htons(dst_port); - /* in UDP, 0 checksum means 'no checksum' */ - udphdr->chksum = 0x0000; - - /* Multicast Loop? */ -#if LWIP_IGMP - if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) && ip_addr_ismulticast(dst_ip)) { - q->flags |= PBUF_FLAG_MCASTLOOP; - } -#endif /* LWIP_IGMP */ - - - /* PCB local address is IP_ANY_ADDR? */ - if (ip_addr_isany(&pcb->local_ip)) { - /* use outgoing network interface IP address as source address */ - src_ip = &(netif->ip_addr); - } else { - /* check if UDP PCB local IP address is correct - * this could be an old address if netif->ip_addr has changed */ - if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) { - /* local_ip doesn't match, drop the packet */ - if (q != p) { - /* free the header pbuf */ - pbuf_free(q); - q = NULL; - /* p is still referenced by the caller, and will live on */ - } - return ERR_VAL; - } - /* use UDP PCB local IP address as source address */ - src_ip = &(pcb->local_ip); - } - - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); - -#if LWIP_UDPLITE - /* UDP Lite protocol? */ - if (pcb->flags & UDP_FLAGS_UDPLITE) { - u16_t chklen, chklen_hdr; - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len)); - /* set UDP message length in UDP header */ - chklen_hdr = chklen = pcb->chksum_len_tx; - if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) { - if (chklen != 0) { - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen)); - } - /* For UDP-Lite, checksum length of 0 means checksum - over the complete packet. (See RFC 3828 chap. 3.1) - At least the UDP-Lite header must be covered by the - checksum, therefore, if chksum_len has an illegal - value, we generate the checksum over the complete - packet to be safe. */ - chklen_hdr = 0; - chklen = q->tot_len; - } - udphdr->len = htons(chklen_hdr); - /* calculate checksum */ -#if CHECKSUM_GEN_UDP - udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, - IP_PROTO_UDPLITE, q->tot_len, -#if !LWIP_CHECKSUM_ON_COPY - chklen); -#else /* !LWIP_CHECKSUM_ON_COPY */ - (have_chksum ? UDP_HLEN : chklen)); - if (have_chksum) { - u32_t acc; - acc = udphdr->chksum + (u16_t)~(chksum); - udphdr->chksum = FOLD_U32T(acc); - } -#endif /* !LWIP_CHECKSUM_ON_COPY */ - - /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udphdr->chksum == 0x0000) { - udphdr->chksum = 0xffff; - } -#endif /* CHECKSUM_GEN_UDP */ - /* output to IP */ - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n")); -#if LWIP_NETIF_HWADDRHINT - netif->addr_hint = &(pcb->addr_hint); -#endif /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); -#if LWIP_NETIF_HWADDRHINT - netif->addr_hint = NULL; -#endif /* LWIP_NETIF_HWADDRHINT*/ - } else -#endif /* LWIP_UDPLITE */ - { /* UDP */ - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); - udphdr->len = htons(q->tot_len); - /* calculate checksum */ -#if CHECKSUM_GEN_UDP - if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { - u16_t udpchksum; -#if LWIP_CHECKSUM_ON_COPY - if (have_chksum) { - u32_t acc; - udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP, - q->tot_len, UDP_HLEN); - acc = udpchksum + (u16_t)~(chksum); - udpchksum = FOLD_U32T(acc); - } else -#endif /* LWIP_CHECKSUM_ON_COPY */ - { - udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); - } - - /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udpchksum == 0x0000) { - udpchksum = 0xffff; - } - udphdr->chksum = udpchksum; - } -#endif /* CHECKSUM_GEN_UDP */ - - /* Determine TTL to use */ -#if LWIP_IGMP - ttl = (ip_addr_ismulticast(dst_ip) ? pcb->mcast_ttl : pcb->ttl); -#else /* LWIP_IGMP */ - ttl = pcb->ttl; -#endif /* LWIP_IGMP */ - - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n")); - /* output to IP */ -#if LWIP_NETIF_HWADDRHINT - netif->addr_hint = &(pcb->addr_hint); -#endif /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output_if(q, src_ip, dst_ip, ttl, pcb->tos, IP_PROTO_UDP, netif); -#if LWIP_NETIF_HWADDRHINT - netif->addr_hint = NULL; -#endif /* LWIP_NETIF_HWADDRHINT*/ - } - /* TODO: must this be increased even if error occured? */ - snmp_inc_udpoutdatagrams(); - - /* did we chain a separate header pbuf earlier? */ - if (q != p) { - /* free the header pbuf */ - pbuf_free(q); - q = NULL; - /* p is still referenced by the caller, and will live on */ - } - - UDP_STATS_INC(udp.xmit); - return err; -} - -/** - * Bind an UDP PCB. - * - * @param pcb UDP PCB to be bound with a local address ipaddr and port. - * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to - * bind to all local interfaces. - * @param port local UDP port to bind with. Use 0 to automatically bind - * to a random port between UDP_LOCAL_PORT_RANGE_START and - * UDP_LOCAL_PORT_RANGE_END. - * - * ipaddr & port are expected to be in the same byte order as in the pcb. - * - * @return lwIP error code. - * - ERR_OK. Successful. No error occured. - * - ERR_USE. The specified ipaddr and port are already bound to by - * another UDP PCB. - * - * @see udp_disconnect() - */ -err_t ICACHE_FLASH_ATTR -udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) -{ - struct udp_pcb *ipcb; - u8_t rebind; - - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = ")); - ip_addr_debug_print(UDP_DEBUG, ipaddr); - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port)); - - rebind = 0; - /* Check for double bind and rebind of the same pcb */ - for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { - /* is this UDP PCB already on active list? */ - if (pcb == ipcb) { - /* pcb may occur at most once in active list */ - LWIP_ASSERT("rebind == 0", rebind == 0); - /* pcb already in list, just rebind */ - rebind = 1; - } - - /* By default, we don't allow to bind to a port that any other udp - PCB is alread bound to, unless *all* PCBs with that port have tha - REUSEADDR flag set. */ -#if SO_REUSE - else if (((pcb->so_options & SOF_REUSEADDR) == 0) && - ((ipcb->so_options & SOF_REUSEADDR) == 0)) { -#else /* SO_REUSE */ - /* port matches that of PCB in list and REUSEADDR not set -> reject */ - else { -#endif /* SO_REUSE */ - if ((ipcb->local_port == port) && - /* IP address matches, or one is IP_ADDR_ANY? */ - (ip_addr_isany(&(ipcb->local_ip)) || - ip_addr_isany(ipaddr) || - ip_addr_cmp(&(ipcb->local_ip), ipaddr))) { - /* other PCB already binds to this local IP and port */ - LWIP_DEBUGF(UDP_DEBUG, - ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); - return ERR_USE; - } - } - } - - ip_addr_set(&pcb->local_ip, ipaddr); - - /* no port specified? */ - if (port == 0) { -#ifndef UDP_LOCAL_PORT_RANGE_START -#define UDP_LOCAL_PORT_RANGE_START 4096 -#define UDP_LOCAL_PORT_RANGE_END 0x7fff -#endif - port = UDP_LOCAL_PORT_RANGE_START; - ipcb = udp_pcbs; - while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) { - if (ipcb->local_port == port) { - /* port is already used by another udp_pcb */ - port++; - /* restart scanning all udp pcbs */ - ipcb = udp_pcbs; - } else { - /* go on with next udp pcb */ - ipcb = ipcb->next; - } - } - if (ipcb != NULL) { - /* no more ports available in local range */ - LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); - return ERR_USE; - } - } - pcb->local_port = port; - snmp_insert_udpidx_tree(pcb); - /* pcb not active yet? */ - if (rebind == 0) { - /* place the PCB on the active list if not already there */ - pcb->next = udp_pcbs; - udp_pcbs = pcb; - } - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n", - ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), - ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), - pcb->local_port)); - return ERR_OK; -} -/** - * Connect an UDP PCB. - * - * This will associate the UDP PCB with the remote address. - * - * @param pcb UDP PCB to be connected with remote address ipaddr and port. - * @param ipaddr remote IP address to connect with. - * @param port remote UDP port to connect with. - * - * @return lwIP error code - * - * ipaddr & port are expected to be in the same byte order as in the pcb. - * - * The udp pcb is bound to a random local port if not already bound. - * - * @see udp_disconnect() - */ -err_t ICACHE_FLASH_ATTR -udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) -{ - struct udp_pcb *ipcb; - - if (pcb->local_port == 0) { - err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); - if (err != ERR_OK) { - return err; - } - } - - ip_addr_set(&pcb->remote_ip, ipaddr); - pcb->remote_port = port; - pcb->flags |= UDP_FLAGS_CONNECTED; -/** TODO: this functionality belongs in upper layers */ -#ifdef LWIP_UDP_TODO - /* Nail down local IP for netconn_addr()/getsockname() */ - if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) { - struct netif *netif; - - if ((netif = ip_route(&(pcb->remote_ip))) == NULL) { - LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr)); - UDP_STATS_INC(udp.rterr); - return ERR_RTE; - } - /** TODO: this will bind the udp pcb locally, to the interface which - is used to route output packets to the remote address. However, we - might want to accept incoming packets on any interface! */ - pcb->local_ip = netif->ip_addr; - } else if (ip_addr_isany(&pcb->remote_ip)) { - pcb->local_ip.addr = 0; - } -#endif - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n", - ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), - ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), - pcb->local_port)); - - /* Insert UDP PCB into the list of active UDP PCBs. */ - for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { - if (pcb == ipcb) { - /* already on the list, just return */ - return ERR_OK; - } - } - /* PCB not yet on the list, add PCB now */ - pcb->next = udp_pcbs; - udp_pcbs = pcb; - return ERR_OK; -} - -/** - * Disconnect a UDP PCB - * - * @param pcb the udp pcb to disconnect. - */ -void ICACHE_FLASH_ATTR -udp_disconnect(struct udp_pcb *pcb) -{ - /* reset remote address association */ - ip_addr_set_any(&pcb->remote_ip); - pcb->remote_port = 0; - /* mark PCB as unconnected */ - pcb->flags &= ~UDP_FLAGS_CONNECTED; -} - -/** - * Set a receive callback for a UDP PCB - * - * This callback will be called when receiving a datagram for the pcb. - * - * @param pcb the pcb for wich to set the recv callback - * @param recv function pointer of the callback function - * @param recv_arg additional argument to pass to the callback function - */ -void ICACHE_FLASH_ATTR -udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) -{ - /* remember recv() callback and user data */ - pcb->recv = recv; - pcb->recv_arg = recv_arg; -} - -/** - * Remove an UDP PCB. - * - * @param pcb UDP PCB to be removed. The PCB is removed from the list of - * UDP PCB's and the data structure is freed from memory. - * - * @see udp_new() - */ -void ICACHE_FLASH_ATTR -udp_remove(struct udp_pcb *pcb) -{ - struct udp_pcb *pcb2; - - snmp_delete_udpidx_tree(pcb); - /* pcb to be removed is first in list? */ - if (udp_pcbs == pcb) { - /* make list start at 2nd pcb */ - udp_pcbs = udp_pcbs->next; - /* pcb not 1st in list */ - } else { - for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { - /* find pcb in udp_pcbs list */ - if (pcb2->next != NULL && pcb2->next == pcb) { - /* remove pcb from list */ - pcb2->next = pcb->next; - } - } - } - memp_free(MEMP_UDP_PCB, pcb); -} - -/** - * Create a UDP PCB. - * - * @return The UDP PCB which was created. NULL if the PCB data structure - * could not be allocated. - * - * @see udp_remove() - */ -struct udp_pcb * ICACHE_FLASH_ATTR -udp_new(void) -{ - struct udp_pcb *pcb; - pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB); - /* could allocate UDP PCB? */ - if (pcb != NULL) { - /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0 - * which means checksum is generated over the whole datagram per default - * (recommended as default by RFC 3828). */ - /* initialize PCB to all zeroes */ - os_memset(pcb, 0, sizeof(struct udp_pcb)); - pcb->ttl = UDP_TTL; -#if LWIP_IGMP - pcb->mcast_ttl = UDP_TTL; -#endif - } - return pcb; -} - -#if UDP_DEBUG -/** - * Print UDP header information for debug purposes. - * - * @param udphdr pointer to the udp header in memory. - */ -void ICACHE_FLASH_ATTR -udp_debug_print(struct udp_hdr *udphdr) -{ - LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n")); - LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", - ntohs(udphdr->src), ntohs(udphdr->dest))); - LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n", - ntohs(udphdr->len), ntohs(udphdr->chksum))); - LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); -} -#endif /* UDP_DEBUG */ - -#endif /* LWIP_UDP */ diff --git a/tools/sdk/lwip/src/netif/etharp.c b/tools/sdk/lwip/src/netif/etharp.c deleted file mode 100644 index 7eb328ace..000000000 --- a/tools/sdk/lwip/src/netif/etharp.c +++ /dev/null @@ -1,1413 +0,0 @@ -/** - * @file - * Address Resolution Protocol module for IP over Ethernet - * - * Functionally, ARP is divided into two parts. The first maps an IP address - * to a physical address when sending a packet, and the second part answers - * requests from other machines for our physical address. - * - * This implementation complies with RFC 826 (Ethernet ARP). It supports - * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 - * if an interface calls etharp_gratuitous(our_netif) upon address change. - */ - -/* - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * Copyright (c) 2003-2004 Leon Woestenberg - * Copyright (c) 2003-2004 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. - * - * This file is part of the lwIP TCP/IP stack. - * - */ - -#include "lwip/opt.h" - -#if LWIP_ARP || LWIP_ETHERNET - -#include "lwip/ip_addr.h" -#include "lwip/def.h" -#include "lwip/ip.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" -#include "netif/etharp.h" - -#if PPPOE_SUPPORT -#include "netif/ppp_oe.h" -#endif /* PPPOE_SUPPORT */ - -#include - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - -const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; -const struct eth_addr ethzero = {{0,0,0,0,0,0}}; - -#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ - -/** the time an ARP entry stays valid after its last update, - * for ARP_TMR_INTERVAL = 5000, this is - * (240 * 5) seconds = 20 minutes. - */ -#define ARP_MAXAGE 240 -/** Re-request a used ARP entry 1 minute before it would expire to prevent - * breaking a steadily used connection because the ARP entry timed out. */ -#define ARP_AGE_REREQUEST_USED (ARP_MAXAGE - 12) -/** the time an ARP entry stays pending after first request, - * for ARP_TMR_INTERVAL = 5000, this is - * (2 * 5) seconds = 10 seconds. - * - * @internal Keep this number at least 2, otherwise it might - * run out instantly if the timeout occurs directly after a request. - */ -#define ARP_MAXPENDING 2 - -#define HWTYPE_ETHERNET 1 - -enum etharp_state { - ETHARP_STATE_EMPTY = 0, - ETHARP_STATE_PENDING, - ETHARP_STATE_STABLE, - ETHARP_STATE_STABLE_REREQUESTING -}; - -struct etharp_entry { -#if ARP_QUEUEING - /** Pointer to queue of pending outgoing packets on this ARP entry. */ - struct etharp_q_entry *q; -#else /* ARP_QUEUEING */ - /** Pointer to a single pending outgoing packet on this ARP entry. */ - struct pbuf *q; -#endif /* ARP_QUEUEING */ - ip_addr_t ipaddr; - struct eth_addr ethaddr; -#if LWIP_SNMP || LWIP_ARP - struct netif *netif; -#endif /* LWIP_SNMP */ - u8_t state; - u8_t ctime; -#if ETHARP_SUPPORT_STATIC_ENTRIES - u8_t static_entry; -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ -}; - -static struct etharp_entry arp_table[ARP_TABLE_SIZE]; - -#if !LWIP_NETIF_HWADDRHINT -static u8_t etharp_cached_entry; -#endif /* !LWIP_NETIF_HWADDRHINT */ - -/** Try hard to create a new entry - we want the IP address to appear in - the cache (even if this means removing an active entry or so). */ -#define ETHARP_FLAG_TRY_HARD 1 -#define ETHARP_FLAG_FIND_ONLY 2 -#define ETHARP_FLAG_STATIC_ENTRY 4 - -#if LWIP_NETIF_HWADDRHINT -#define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \ - *((netif)->addr_hint) = (hint); -#else /* LWIP_NETIF_HWADDRHINT */ -#define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint)) -#endif /* LWIP_NETIF_HWADDRHINT */ - -static err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags); - - -/* Some checks, instead of etharp_init(): */ -#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) - #error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h" -#endif - - -#if ARP_QUEUEING -/** - * Free a complete queue of etharp entries - * - * @param q a qeueue of etharp_q_entry's to free - */ -static void -free_etharp_q(struct etharp_q_entry *q) -{ - struct etharp_q_entry *r; - LWIP_ASSERT("q != NULL", q != NULL); - LWIP_ASSERT("q->p != NULL", q->p != NULL); - while (q) { - r = q; - q = q->next; - LWIP_ASSERT("r->p != NULL", (r->p != NULL)); - pbuf_free(r->p); - memp_free(MEMP_ARP_QUEUE, r); - } -} -#else /* ARP_QUEUEING */ - -/** Compatibility define: free the queued pbuf */ -#define free_etharp_q(q) pbuf_free(q) - -#endif /* ARP_QUEUEING */ - -/** Clean up ARP table entries */ -static void ICACHE_FLASH_ATTR -free_entry(int i) -{ - /* remove from SNMP ARP index tree */ - snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); - /* and empty packet queue */ - if (arp_table[i].q != NULL) { - /* remove all queued packets */ - LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); - free_etharp_q(arp_table[i].q); - arp_table[i].q = NULL; - } - /* recycle entry for re-use */ - arp_table[i].state = ETHARP_STATE_EMPTY; -#if ETHARP_SUPPORT_STATIC_ENTRIES - arp_table[i].static_entry = 0; -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ -#ifdef LWIP_DEBUG - /* for debugging, clean out the complete entry */ - arp_table[i].ctime = 0; -#if LWIP_SNMP - arp_table[i].netif = NULL; -#endif /* LWIP_SNMP */ - ip_addr_set_zero(&arp_table[i].ipaddr); - arp_table[i].ethaddr = ethzero; -#endif /* LWIP_DEBUG */ -} - -/** - * Clears expired entries in the ARP table. - * - * This function should be called every ETHARP_TMR_INTERVAL milliseconds (5 seconds), - * in order to expire entries in the ARP table. - */ -void -etharp_tmr(void) -{ - u8_t i; - - LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); - /* remove expired entries from the ARP table */ - for (i = 0; i < ARP_TABLE_SIZE; ++i) { - u8_t state = arp_table[i].state; - if (state != ETHARP_STATE_EMPTY -#if ETHARP_SUPPORT_STATIC_ENTRIES - && (arp_table[i].static_entry == 0) -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - ) { - arp_table[i].ctime++; - if ((arp_table[i].ctime >= ARP_MAXAGE) || - ((arp_table[i].state == ETHARP_STATE_PENDING) && - (arp_table[i].ctime >= ARP_MAXPENDING))) { - /* pending or stable entry has become old! */ - LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", - arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); - /* clean up entries that have just been expired */ - free_entry(i); - } - else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) { - /* Reset state to stable, so that the next transmitted packet will - re-send an ARP request. */ - arp_table[i].state = ETHARP_STATE_STABLE; - } -#if ARP_QUEUEING - /* still pending entry? (not expired) */ - if (arp_table[i].state == ETHARP_STATE_PENDING) { - /* resend an ARP query here? */ - } -#endif /* ARP_QUEUEING */ - } - } -} - -/** - * Search the ARP table for a matching or new entry. - * - * If an IP address is given, return a pending or stable ARP entry that matches - * the address. If no match is found, create a new entry with this address set, - * but in state ETHARP_EMPTY. The caller must check and possibly change the - * state of the returned entry. - * - * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY. - * - * In all cases, attempt to create new entries from an empty entry. If no - * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle - * old entries. Heuristic choose the least important entry for recycling. - * - * @param ipaddr IP address to find in ARP cache, or to add if not found. - * @param flags @see definition of ETHARP_FLAG_* - * @param netif netif related to this address (used for NETIF_HWADDRHINT) - * - * @return The ARP entry index that matched or is created, ERR_MEM if no - * entry is found or could be recycled. - */ -static s8_t ICACHE_FLASH_ATTR -find_entry(ip_addr_t *ipaddr, u8_t flags) -{ - s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; - s8_t empty = ARP_TABLE_SIZE; - u8_t i = 0, age_pending = 0, age_stable = 0; - /* oldest entry with packets on queue */ - s8_t old_queue = ARP_TABLE_SIZE; - /* its age */ - u8_t age_queue = 0; - - /** - * a) do a search through the cache, remember candidates - * b) select candidate entry - * c) create new entry - */ - - /* a) in a single search sweep, do all of this - * 1) remember the first empty entry (if any) - * 2) remember the oldest stable entry (if any) - * 3) remember the oldest pending entry without queued packets (if any) - * 4) remember the oldest pending entry with queued packets (if any) - * 5) search for a matching IP entry, either pending or stable - * until 5 matches, or all entries are searched for. - */ - - for (i = 0; i < ARP_TABLE_SIZE; ++i) { - u8_t state = arp_table[i].state; - /* no empty entry found yet and now we do find one? */ - if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) { - LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i)); - /* remember first empty entry */ - empty = i; - } else if (state != ETHARP_STATE_EMPTY) { - LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE", - state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE); - /* if given, does IP address match IP address in ARP entry? */ - if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i)); - /* found exact IP address match, simply bail out */ - return i; - } - /* pending entry? */ - if (state == ETHARP_STATE_PENDING) { - /* pending with queued packets? */ - if (arp_table[i].q != NULL) { - if (arp_table[i].ctime >= age_queue) { - old_queue = i; - age_queue = arp_table[i].ctime; - } - } else - /* pending without queued packets? */ - { - if (arp_table[i].ctime >= age_pending) { - old_pending = i; - age_pending = arp_table[i].ctime; - } - } - /* stable entry? */ - } else if (state >= ETHARP_STATE_STABLE) { -#if ETHARP_SUPPORT_STATIC_ENTRIES - /* don't record old_stable for static entries since they never expire */ - if (arp_table[i].static_entry == 0) -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - { - /* remember entry with oldest stable entry in oldest, its age in maxtime */ - if (arp_table[i].ctime >= age_stable) { - old_stable = i; - age_stable = arp_table[i].ctime; - } - } - } - } - } - /* { we have no match } => try to create a new entry */ - - /* don't create new entry, only search? */ - if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) || - /* or no empty entry found and not allowed to recycle? */ - ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n")); - return (s8_t)ERR_MEM; - } - - /* b) choose the least destructive entry to recycle: - * 1) empty entry - * 2) oldest stable entry - * 3) oldest pending entry without queued packets - * 4) oldest pending entry with queued packets - * - * { ETHARP_FLAG_TRY_HARD is set at this point } - */ - - /* 1) empty entry available? */ - if (empty < ARP_TABLE_SIZE) { - i = empty; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); - } else { - /* 2) found recyclable stable entry? */ - if (old_stable < ARP_TABLE_SIZE) { - /* recycle oldest stable*/ - i = old_stable; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); - /* no queued packets should exist on stable entries */ - LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); - /* 3) found recyclable pending entry without queued packets? */ - } else if (old_pending < ARP_TABLE_SIZE) { - /* recycle oldest pending */ - i = old_pending; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); - /* 4) found recyclable pending entry with queued packets? */ - } else if (old_queue < ARP_TABLE_SIZE) { - /* recycle oldest pending (queued packets are free in free_entry) */ - i = old_queue; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); - /* no empty or recyclable entries found */ - } else { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty or recyclable entries found\n")); - return (s8_t)ERR_MEM; - } - - /* { empty or recyclable entry found } */ - LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); - free_entry(i); - } - - LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); - LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY", - arp_table[i].state == ETHARP_STATE_EMPTY); - - /* IP address given? */ - if (ipaddr != NULL) { - /* set IP address */ - ip_addr_copy(arp_table[i].ipaddr, *ipaddr); - } - arp_table[i].ctime = 0; -#if ETHARP_SUPPORT_STATIC_ENTRIES - arp_table[i].static_entry = 0; -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - return (err_t)i; -} - -/** - * Send an IP packet on the network using netif->linkoutput - * The ethernet header is filled in before sending. - * - * @params netif the lwIP network interface on which to send the packet - * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header - * @params src the source MAC address to be copied into the ethernet header - * @params dst the destination MAC address to be copied into the ethernet header - * @return ERR_OK if the packet was sent, any other err_t on failure - */ -static err_t ICACHE_FLASH_ATTR -etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) -{ - struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; - - LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", - (netif->hwaddr_len == ETHARP_HWADDR_LEN)); - ETHADDR32_COPY(ðhdr->dest, dst); - ETHADDR16_COPY(ðhdr->src, src); - ethhdr->type = PP_HTONS(ETHTYPE_IP); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p)); - /* send the packet */ - return netif->linkoutput(netif, p); -} - -/** - * Update (or insert) a IP/MAC address pair in the ARP cache. - * - * If a pending entry is resolved, any queued packets will be sent - * at this point. - * - * @param netif netif related to this entry (used for NETIF_ADDRHINT) - * @param ipaddr IP address of the inserted ARP entry. - * @param ethaddr Ethernet address of the inserted ARP entry. - * @param flags @see definition of ETHARP_FLAG_* - * - * @return - * - ERR_OK Succesfully updated ARP cache. - * - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD was set. - * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. - * - * @see pbuf_free() - */ -static err_t ICACHE_FLASH_ATTR -update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags) -{ - s8_t i; - LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", - ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), - ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], - ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); - /* non-unicast address? */ - if (ip_addr_isany(ipaddr) || - ip_addr_isbroadcast(ipaddr, netif) || - ip_addr_ismulticast(ipaddr)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n")); - return ERR_ARG; - } - /* find or create ARP entry */ - i = find_entry(ipaddr, flags); - /* bail out if no entry could be found */ - if (i < 0) { - return (err_t)i; - } - -#if ETHARP_SUPPORT_STATIC_ENTRIES - if (flags & ETHARP_FLAG_STATIC_ENTRY) { - /* record static type */ - arp_table[i].static_entry = 1; - } -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - - /* mark it stable */ - arp_table[i].state = ETHARP_STATE_STABLE; - -#if LWIP_SNMP - /* record network interface */ - arp_table[i].netif = netif; -#endif /* LWIP_SNMP */ - /* insert in SNMP ARP index tree */ - snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); - - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); - /* update address */ - ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr); - /* reset time stamp */ - arp_table[i].ctime = 0; - /* this is where we will send out queued packets! */ -#if ARP_QUEUEING - while (arp_table[i].q != NULL) { - struct pbuf *p; - /* remember remainder of queue */ - struct etharp_q_entry *q = arp_table[i].q; - /* pop first item off the queue */ - arp_table[i].q = q->next; - /* get the packet pointer */ - p = q->p; - /* now queue entry can be freed */ - memp_free(MEMP_ARP_QUEUE, q); -#else /* ARP_QUEUEING */ - if (arp_table[i].q != NULL) { - struct pbuf *p = arp_table[i].q; - arp_table[i].q = NULL; -#endif /* ARP_QUEUEING */ - /* send the queued IP packet */ - etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr); - /* free the queued IP packet */ - pbuf_free(p); - } - return ERR_OK; -} - -#if ETHARP_SUPPORT_STATIC_ENTRIES -/** Add a new static entry to the ARP table. If an entry exists for the - * specified IP address, this entry is overwritten. - * If packets are queued for the specified IP address, they are sent out. - * - * @param ipaddr IP address for the new static entry - * @param ethaddr ethernet address for the new static entry - * @return @see return values of etharp_add_static_entry - */ -err_t -etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr) -{ - struct netif *netif; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_add_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", - ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), - ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], - ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); - - netif = ip_route(ipaddr); - if (netif == NULL) { - return ERR_RTE; - } - - return update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY); -} - -/** Remove a static entry from the ARP table previously added with a call to - * etharp_add_static_entry. - * - * @param ipaddr IP address of the static entry to remove - * @return ERR_OK: entry removed - * ERR_MEM: entry wasn't found - * ERR_ARG: entry wasn't a static entry but a dynamic one - */ -err_t -etharp_remove_static_entry(ip_addr_t *ipaddr) -{ - s8_t i; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); - - /* find or create ARP entry */ - i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); - /* bail out if no entry could be found */ - if (i < 0) { - return (err_t)i; - } - - if ((arp_table[i].state != ETHARP_STATE_STABLE) || - (arp_table[i].static_entry == 0)) { - /* entry wasn't a static entry, cannot remove it */ - return ERR_ARG; - } - /* entry found, free it */ - free_entry(i); - return ERR_OK; -} -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - -/** - * Remove all ARP table entries of the specified netif. - * - * @param netif points to a network interface - */ -void ICACHE_FLASH_ATTR etharp_cleanup_netif(struct netif *netif) -{ - u8_t i; - - for (i = 0; i < ARP_TABLE_SIZE; ++i) { - u8_t state = arp_table[i].state; - if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) { - free_entry(i); - } - } -} - -/** - * Finds (stable) ethernet/IP address pair from ARP table - * using interface and IP address index. - * @note the addresses in the ARP table are in network order! - * - * @param netif points to interface index - * @param ipaddr points to the (network order) IP address index - * @param eth_ret points to return pointer - * @param ip_ret points to return pointer - * @return table index if found, -1 otherwise - */ -s8_t -etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, - struct eth_addr **eth_ret, ip_addr_t **ip_ret) -{ - s8_t i; - - LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL", - eth_ret != NULL && ip_ret != NULL); - - LWIP_UNUSED_ARG(netif); - - i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); - if((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { - *eth_ret = &arp_table[i].ethaddr; - *ip_ret = &arp_table[i].ipaddr; - return i; - } - return -1; -} - -#if ETHARP_TRUST_IP_MAC -/** - * Updates the ARP table using the given IP packet. - * - * Uses the incoming IP packet's source address to update the - * ARP cache for the local network. The function does not alter - * or free the packet. This function must be called before the - * packet p is passed to the IP layer. - * - * @param netif The lwIP network interface on which the IP packet pbuf arrived. - * @param p The IP packet that arrived on netif. - * - * @return NULL - * - * @see pbuf_free() - */ -static void ICACHE_FLASH_ATTR -etharp_ip_input(struct netif *netif, struct pbuf *p) -{ - struct eth_hdr *ethhdr; - struct ip_hdr *iphdr; - ip_addr_t iphdr_src; - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - - /* Only insert an entry if the source IP address of the - incoming IP packet comes from a host on the local network. */ - ethhdr = (struct eth_hdr *)p->payload; - iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); -#if ETHARP_SUPPORT_VLAN - if (ethhdr->type == ETHTYPE_VLAN) { - iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); - } -#endif /* ETHARP_SUPPORT_VLAN */ - - ip_addr_copy(iphdr_src, iphdr->src); - - /* source is not on the local network? */ - if (!ip_addr_netcmp(&iphdr_src, &(netif->ip_addr), &(netif->netmask))) { - /* do nothing */ - return; - } - - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n")); - /* update the source IP address in the cache, if present */ - /* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk - * back soon (for example, if the destination IP address is ours. */ - update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY); -} -#endif /* ETHARP_TRUST_IP_MAC */ - -/** - * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache - * send out queued IP packets. Updates cache with snooped address pairs. - * - * Should be called for incoming ARP packets. The pbuf in the argument - * is freed by this function. - * - * @param netif The lwIP network interface on which the ARP packet pbuf arrived. - * @param ethaddr Ethernet address of netif. - * @param p The ARP packet that arrived on netif. Is freed by this function. - * - * @return NULL - * - * @see pbuf_free() - */ -static void ICACHE_FLASH_ATTR -etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) -{ - struct etharp_hdr *hdr; - struct eth_hdr *ethhdr; - /* these are aligned properly, whereas the ARP header fields might not be */ - ip_addr_t sipaddr, dipaddr; - u8_t for_us; -#if LWIP_AUTOIP - const u8_t * ethdst_hwaddr; -#endif /* LWIP_AUTOIP */ -#ifdef EBUF_LWIP - struct pbuf *q; -#endif /* EBUF_LWIP */ - - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - - /* drop short ARP packets: we have to check for p->len instead of p->tot_len here - since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */ - if (p->len < SIZEOF_ETHARP_PACKET) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, - (s16_t)SIZEOF_ETHARP_PACKET)); - ETHARP_STATS_INC(etharp.lenerr); - ETHARP_STATS_INC(etharp.drop); - pbuf_free(p); - return; - } - - ethhdr = (struct eth_hdr *)p->payload; - hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); -#if ETHARP_SUPPORT_VLAN - if (ethhdr->type == ETHTYPE_VLAN) { - hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); - } -#endif /* ETHARP_SUPPORT_VLAN */ - - /* RFC 826 "Packet Reception": */ - if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) || - (hdr->hwlen != ETHARP_HWADDR_LEN) || - (hdr->protolen != sizeof(ip_addr_t)) || - (hdr->proto != PP_HTONS(ETHTYPE_IP)) || - (ethhdr->type != PP_HTONS(ETHTYPE_ARP))) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", - hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen, ethhdr->type)); - ETHARP_STATS_INC(etharp.proterr); - ETHARP_STATS_INC(etharp.drop); - pbuf_free(p); - return; - } - ETHARP_STATS_INC(etharp.recv); - -#if LWIP_AUTOIP - /* We have to check if a host already has configured our random - * created link local address and continously check if there is - * a host with this IP-address so we can detect collisions */ - autoip_arp_reply(netif, hdr); -#endif /* LWIP_AUTOIP */ - - /* 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); - - /* this interface is not configured? */ - if (ip_addr_isany(&netif->ip_addr)) { - for_us = 0; - } else { - /* ARP packet directed to us? */ - for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr)); - } - - /* ARP message directed to us? - -> add IP address in ARP cache; assume requester wants to talk to us, - can result in directly sending the queued packets for this host. - ARP message not directed to us? - -> update the source IP address in the cache, if present */ - update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), - for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY); - - /* now act on the message itself */ - switch (hdr->opcode) { - /* ARP request? */ - case PP_HTONS(ARP_REQUEST): - /* ARP request. If it asked for our address, we send out a - * reply. In any case, we time-stamp any existing ARP entry, - * and possiby send out an IP packet that was queued on it. */ - - LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP request\n")); - /* ARP request for our address? */ - if (for_us) { - - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n")); - /* Re-use pbuf to send ARP reply. - Since we are re-using an existing pbuf, we can't call etharp_raw since - that would allocate a new pbuf. */ - hdr->opcode = htons(ARP_REPLY); - - IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr); - IPADDR2_COPY(&hdr->sipaddr, &netif->ip_addr); - - LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", - (netif->hwaddr_len == ETHARP_HWADDR_LEN)); -#if LWIP_AUTOIP - /* If we are using Link-Local, all ARP packets that contain a Link-Local - * 'sender IP address' MUST be sent using link-layer broadcast instead of - * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ - ethdst_hwaddr = ip_addr_islinklocal(&netif->ip_addr) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr; -#endif /* LWIP_AUTOIP */ - - ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr); -#if LWIP_AUTOIP - ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr); -#else /* LWIP_AUTOIP */ - ETHADDR16_COPY(ðhdr->dest, &hdr->shwaddr); -#endif /* LWIP_AUTOIP */ - ETHADDR16_COPY(&hdr->shwaddr, ethaddr); - ETHADDR16_COPY(ðhdr->src, ethaddr); - - /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header - are already correct, we tested that before */ -#ifdef EBUF_LWIP - /* - * don't do flip-flop here... do a copy here. - * otherwise, we need to handle existing pbuf->eb in ieee80211_output.c - */ - - q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if (q != NULL) { - pbuf_copy(q, p); - //pbuf_free(p); - } else { - LWIP_ASSERT("q != NULL", q != NULL); - } - - netif->linkoutput(netif, q); - pbuf_free(q); -#else - - /* return ARP reply */ - netif->linkoutput(netif, p); -#endif /* ESF_LWIP */ - /* we are not configured? */ - } else if (ip_addr_isany(&netif->ip_addr)) { - /* { for_us == 0 and netif->ip_addr.addr == 0 } */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n")); - /* request was not directed to us */ - } else { - /* { for_us == 0 and netif->ip_addr.addr != 0 } */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n")); - } - break; - case PP_HTONS(ARP_REPLY): - /* ARP reply. We already updated the ARP cache earlier. */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n")); -#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) - /* DHCP wants to know about ARP replies from any host with an - * IP address also offered to us by the DHCP server. We do not - * want to take a duplicate IP address on a single network. - * @todo How should we handle redundant (fail-over) interfaces? */ - dhcp_arp_reply(netif, &sipaddr); -#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */ - break; - default: - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode))); - ETHARP_STATS_INC(etharp.err); - break; - } - /* free ARP packet */ - pbuf_free(p); -} - -/** Just a small helper function that sends a pbuf to an ethernet address - * in the arp_table specified by the index 'arp_idx'. - */ -static err_t ICACHE_FLASH_ATTR -etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx) -{ - LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE", - arp_table[arp_idx].state >= ETHARP_STATE_STABLE); - /* if arp table entry is about to expire: re-request it, - but only if its state is ETHARP_STATE_STABLE to prevent flooding the - network with ARP requests if this address is used frequently. */ - if ((arp_table[arp_idx].state == ETHARP_STATE_STABLE) && - (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED)) { - if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) { - arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING; - } - } - - return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), - &arp_table[arp_idx].ethaddr); -} - -/** - * Resolve and fill-in Ethernet address header for outgoing IP packet. - * - * For IP multicast and broadcast, corresponding Ethernet addresses - * are selected and the packet is transmitted on the link. - * - * For unicast addresses, the packet is submitted to etharp_query(). In - * case the IP address is outside the local network, the IP address of - * the gateway is used. - * - * @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 ipaddr The IP address of the packet destination. - * - * @return - * - ERR_RTE No route to destination (no gateway to external networks), - * or the return type of either etharp_query() or etharp_send_ip(). - */ -err_t -etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) -{ - struct eth_addr *dest, mcastaddr; - - /* make room for Ethernet header - should not fail */ - if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { - /* bail out */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("etharp_output: could not allocate room for header.\n")); - LINK_STATS_INC(link.lenerr); - return ERR_BUF; - } - - /* assume unresolved Ethernet address */ - dest = NULL; - /* Determine on destination hardware address. Broadcasts and multicasts - * are special, other IP addresses are looked up in the ARP table. */ - - /* broadcast destination IP address? */ - if (ip_addr_isbroadcast(ipaddr, netif)) { - /* broadcast on Ethernet also */ - dest = (struct eth_addr *)ðbroadcast; - /* multicast destination IP address? */ - } else if (ip_addr_ismulticast(ipaddr)) { - /* Hash IP multicast address to MAC address.*/ - mcastaddr.addr[0] = 0x01; - mcastaddr.addr[1] = 0x00; - mcastaddr.addr[2] = 0x5e; - mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; - mcastaddr.addr[4] = ip4_addr3(ipaddr); - mcastaddr.addr[5] = ip4_addr4(ipaddr); - /* destination Ethernet address is multicast */ - dest = &mcastaddr; - /* unicast destination IP address? */ - } else { - s8_t i; - /* outside local network? if so, this can neither be a global broadcast nor - a subnet broadcast. */ - if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) && - !ip_addr_islinklocal(ipaddr)) { -#if LWIP_AUTOIP - struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload + - sizeof(struct eth_hdr)); - /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with - a link-local source address must always be "directly to its destination - on the same physical link. The host MUST NOT send the packet to any - router for forwarding". */ - if (!ip_addr_islinklocal(&iphdr->src)) -#endif /* LWIP_AUTOIP */ - { - /* interface has default gateway? */ - if (!ip_addr_isany(&netif->gw)) { - /* send to hardware address of default gateway IP address */ - ipaddr = &(netif->gw); - /* no default gateway available */ - } else { - /* no route to destination error (default gateway missing) */ - return ERR_RTE; - } - } - } -#if LWIP_NETIF_HWADDRHINT - if (netif->addr_hint != NULL) { - /* per-pcb cached entry was given */ - u8_t etharp_cached_entry = *(netif->addr_hint); - if (etharp_cached_entry < ARP_TABLE_SIZE) { -#endif /* LWIP_NETIF_HWADDRHINT */ - if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) && - (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr))) { - /* the per-pcb-cached entry is stable and the right one! */ - ETHARP_STATS_INC(etharp.cachehit); - return etharp_output_to_arp_index(netif, q, etharp_cached_entry); - } -#if LWIP_NETIF_HWADDRHINT - } - } -#endif /* LWIP_NETIF_HWADDRHINT */ - /* find stable entry: do this here since this is a critical path for - throughput and etharp_find_entry() is kind of slow */ - for (i = 0; i < ARP_TABLE_SIZE; i++) { - if ((arp_table[i].state >= ETHARP_STATE_STABLE) && - (ip_addr_cmp(ipaddr, &arp_table[i].ipaddr))) { - /* found an existing, stable entry */ - ETHARP_SET_HINT(netif, i); - return etharp_output_to_arp_index(netif, q, i); - } - } - /* queue on destination Ethernet address belonging to ipaddr */ - return etharp_query(netif, ipaddr, q); - } - - /* continuation for multicast/broadcast destinations */ - /* obtain source Ethernet address of the given interface */ - /* send packet directly on the link */ - return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest); -} - -/** - * Send an ARP request for the given IP address and/or queue a packet. - * - * If the IP address was not yet in the cache, a pending ARP cache entry - * is added and an ARP request is sent for the given address. The packet - * is queued on this entry. - * - * If the IP address was already pending in the cache, a new ARP request - * is sent for the given address. The packet is queued on this entry. - * - * If the IP address was already stable in the cache, and a packet is - * given, it is directly sent and no ARP request is sent out. - * - * If the IP address was already stable in the cache, and no packet is - * given, an ARP request is sent out. - * - * @param netif The lwIP network interface on which ipaddr - * must be queried for. - * @param ipaddr The IP address to be resolved. - * @param q If non-NULL, a pbuf that must be delivered to the IP address. - * q is not freed by this function. - * - * @note q must only be ONE packet, not a packet queue! - * - * @return - * - ERR_BUF Could not make room for Ethernet header. - * - ERR_MEM Hardware address unknown, and no more ARP entries available - * to query for address or queue the packet. - * - ERR_MEM Could not queue packet due to memory shortage. - * - ERR_RTE No route to destination (no gateway to external networks). - * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. - * - */ -err_t -etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q) -{ - struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr; - err_t result = ERR_MEM; - s8_t i; /* ARP entry index */ - - /* non-unicast address? */ - if (ip_addr_isbroadcast(ipaddr, netif) || - ip_addr_ismulticast(ipaddr) || - ip_addr_isany(ipaddr)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n")); - return ERR_ARG; - } - - /* find entry in ARP cache, ask to create entry if queueing packet */ - i = find_entry(ipaddr, ETHARP_FLAG_TRY_HARD); - - /* could not find or create entry? */ - if (i < 0) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n")); - if (q) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n")); - ETHARP_STATS_INC(etharp.memerr); - } - return (err_t)i; - } - - /* mark a fresh entry as pending (we just sent a request) */ - if (arp_table[i].state == ETHARP_STATE_EMPTY) { - arp_table[i].state = ETHARP_STATE_PENDING; - } - - /* { i is either a STABLE or (new or existing) PENDING entry } */ - LWIP_ASSERT("arp_table[i].state == PENDING or STABLE", - ((arp_table[i].state == ETHARP_STATE_PENDING) || - (arp_table[i].state >= ETHARP_STATE_STABLE))); - - /* do we have a pending entry? or an implicit query request? */ - if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) { - /* try to resolve it; send out ARP request */ - result = etharp_request(netif, ipaddr); - if (result != ERR_OK) { - /* ARP request couldn't be sent */ - /* We don't re-send arp request in etharp_tmr, but we still queue packets, - since this failure could be temporary, and the next packet calling - etharp_query again could lead to sending the queued packets. */ - } - if (q == NULL) { - return result; - } - } - - /* packet given? */ - LWIP_ASSERT("q != NULL", q != NULL); - /* stable entry? */ - if (arp_table[i].state >= ETHARP_STATE_STABLE) { - /* we have a valid IP->Ethernet address mapping */ - ETHARP_SET_HINT(netif, i); - /* send the packet */ - result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr)); - /* pending entry? (either just created or already pending */ - } else if (arp_table[i].state == ETHARP_STATE_PENDING) { - /* entry is still pending, queue the given packet 'q' */ - struct pbuf *p; - int copy_needed = 0; - /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but - * to copy the whole queue into a new PBUF_RAM (see bug #11400) - * PBUF_ROMs can be left as they are, since ROM must not get changed. */ - p = q; - while (p) { - LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); - if(p->type != PBUF_ROM) { - copy_needed = 1; - break; - } - p = p->next; - } - if(copy_needed) { - /* copy the whole packet into new pbufs */ - p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if(p != NULL) { - if (pbuf_copy(p, q) != ERR_OK) { - pbuf_free(p); - p = NULL; - } - } - } else { - /* referencing the old pbuf is enough */ - p = q; - pbuf_ref(p); - } - /* packet could be taken over? */ - if (p != NULL) { - /* queue packet ... */ -#if ARP_QUEUEING - struct etharp_q_entry *new_entry; - /* allocate a new arp queue entry */ - new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE); - if (new_entry != NULL) { - unsigned int qlen = 0; - new_entry->next = 0; - new_entry->p = p; - if(arp_table[i].q != NULL) { - /* queue was already existent, append the new entry to the end */ - struct etharp_q_entry *r; - r = arp_table[i].q; - qlen++; - while (r->next != NULL) { - r = r->next; - qlen++; - } - r->next = new_entry; - } else { - /* queue did not exist, first item in queue */ - arp_table[i].q = new_entry; - } - if(qlen >= 3) { - struct etharp_q_entry *old; - old = arp_table[i].q; - arp_table[i].q = arp_table[i].q->next; - pbuf_free(old->p); - memp_free(MEM_ARP_QUEUE, old); - } - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); - result = ERR_OK; - } else { - /* the pool MEMP_ARP_QUEUE is empty */ - pbuf_free(p); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); - result = ERR_MEM; - } -#else /* ARP_QUEUEING */ - /* always queue one packet per ARP request only, freeing a previously queued packet */ - if (arp_table[i].q != NULL) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); - pbuf_free(arp_table[i].q); - } - arp_table[i].q = p; - result = ERR_OK; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); -#endif /* ARP_QUEUEING */ - } else { - ETHARP_STATS_INC(etharp.memerr); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); - result = ERR_MEM; - } - } - return result; -} - -/** - * Send a raw ARP packet (opcode and all addresses can be modified) - * - * @param netif the lwip network interface on which to send the ARP packet - * @param ethsrc_addr the source MAC address for the ethernet header - * @param ethdst_addr the destination MAC address for the ethernet header - * @param hwsrc_addr the source MAC address for the ARP protocol header - * @param ipsrc_addr the source IP address for the ARP protocol header - * @param hwdst_addr the destination MAC address for the ARP protocol header - * @param ipdst_addr the destination IP address for the ARP protocol header - * @param opcode the type of the ARP packet - * @return ERR_OK if the ARP packet has been sent - * ERR_MEM if the ARP packet couldn't be allocated - * any other err_t on failure - */ -#if !LWIP_AUTOIP -static -#endif /* LWIP_AUTOIP */ -err_t ICACHE_FLASH_ATTR -etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, - const struct eth_addr *ethdst_addr, - const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr, - const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr, - const u16_t opcode) -{ - struct pbuf *p; - err_t result = ERR_OK; - struct eth_hdr *ethhdr; - struct etharp_hdr *hdr; -#if LWIP_AUTOIP - const u8_t * ethdst_hwaddr; -#endif /* LWIP_AUTOIP */ - - /* allocate a pbuf for the outgoing ARP request packet */ - p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM); - /* could allocate a pbuf for an ARP request? */ - if (p == NULL) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("etharp_raw: could not allocate pbuf for ARP request.\n")); - ETHARP_STATS_INC(etharp.memerr); - return ERR_MEM; - } - LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", - (p->len >= SIZEOF_ETHARP_PACKET)); - - ethhdr = (struct eth_hdr *)p->payload; - hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); - hdr->opcode = htons(opcode); - - LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", - (netif->hwaddr_len == ETHARP_HWADDR_LEN)); -#if LWIP_AUTOIP - /* If we are using Link-Local, all ARP packets that contain a Link-Local - * 'sender IP address' MUST be sent using link-layer broadcast instead of - * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ - ethdst_hwaddr = ip_addr_islinklocal(ipsrc_addr) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr; -#endif /* LWIP_AUTOIP */ - /* Write the ARP MAC-Addresses */ - ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr); - ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr); - /* Write the Ethernet MAC-Addresses */ -#if LWIP_AUTOIP - ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr); -#else /* LWIP_AUTOIP */ - ETHADDR16_COPY(ðhdr->dest, ethdst_addr); -#endif /* LWIP_AUTOIP */ - ETHADDR16_COPY(ðhdr->src, ethsrc_addr); - /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without - * structure packing. */ - IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr); - IPADDR2_COPY(&hdr->dipaddr, ipdst_addr); - - hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET); - hdr->proto = PP_HTONS(ETHTYPE_IP); - /* set hwlen and protolen */ - hdr->hwlen = ETHARP_HWADDR_LEN; - hdr->protolen = sizeof(ip_addr_t); - - ethhdr->type = PP_HTONS(ETHTYPE_ARP); - /* send ARP query */ - result = netif->linkoutput(netif, p); - ETHARP_STATS_INC(etharp.xmit); - /* free ARP query packet */ - pbuf_free(p); - p = NULL; - /* could not allocate pbuf for ARP request */ - - return result; -} - -/** - * Send an ARP request packet asking for ipaddr. - * - * @param netif the lwip network interface on which to send the request - * @param ipaddr the IP address for which to ask - * @return ERR_OK if the request has been sent - * ERR_MEM if the ARP packet couldn't be allocated - * any other err_t on failure - */ -err_t -etharp_request(struct netif *netif, ip_addr_t *ipaddr) -{ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); - return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, - (struct eth_addr *)netif->hwaddr, &netif->ip_addr, ðzero, - ipaddr, ARP_REQUEST); -} -#endif /* LWIP_ARP */ - -/** - * Process received ethernet frames. Using this function instead of directly - * calling ip_input and passing ARP frames through etharp in ethernetif_input, - * the ARP cache is protected from concurrent access. - * - * @param p the recevied packet, p->payload pointing to the ethernet header - * @param netif the network interface on which the packet was received - */ -err_t -ethernet_input(struct pbuf *p, struct netif *netif) -{ - struct eth_hdr* ethhdr; - u16_t type; - s16_t ip_hdr_offset = SIZEOF_ETH_HDR; - - if (p->len <= SIZEOF_ETH_HDR) { - /* a packet with only an ethernet header (or less) is not valid for us modify by ives at 2014.4.24*/ - ETHARP_STATS_INC(etharp.proterr); - ETHARP_STATS_INC(etharp.drop); - goto free_and_return; - } - - /* points to packet payload, which starts with an Ethernet header */ - ethhdr = (struct eth_hdr *)p->payload; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, - ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n", - (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], - (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], - (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], - (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], - (unsigned)htons(ethhdr->type))); - - type = ethhdr->type; -#if ETHARP_SUPPORT_VLAN - if (type == PP_HTONS(ETHTYPE_VLAN)) { - struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR); - if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) { - /* a packet with only an ethernet/vlan header (or less) is not valid for us modify by ives at 2014.4.24*/ - ETHARP_STATS_INC(etharp.proterr); - ETHARP_STATS_INC(etharp.drop); - goto free_and_return; - } -#ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */ - if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { - /* silently ignore this packet: not for our VLAN */ - pbuf_free(p); - return ERR_OK; - } -#endif /* ETHARP_VLAN_CHECK */ - type = vlan->tpid; - ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; - } -#endif /* ETHARP_SUPPORT_VLAN */ - -#if LWIP_ARP_FILTER_NETIF - netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type)); -#endif /* LWIP_ARP_FILTER_NETIF*/ - - switch (type) { -#if LWIP_ARP - /* IP packet? */ - case PP_HTONS(ETHTYPE_IP): - if (!(netif->flags & NETIF_FLAG_ETHARP)) { - goto free_and_return; - } -#if ETHARP_TRUST_IP_MAC - /* update ARP table */ - etharp_ip_input(netif, p); -#endif /* ETHARP_TRUST_IP_MAC */ - /* skip Ethernet header */ - if(pbuf_header(p, -ip_hdr_offset)) { - LWIP_ASSERT("Can't move over header in packet", 0); - goto free_and_return; - } else { - /* pass to IP layer */ - ip_input(p, netif); - } - break; - - case PP_HTONS(ETHTYPE_ARP): - if (!(netif->flags & NETIF_FLAG_ETHARP)) { - goto free_and_return; - } - /* pass p to ARP module */ - etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p); - break; -#endif /* LWIP_ARP */ -#if PPPOE_SUPPORT - case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */ - pppoe_disc_input(netif, p); - break; - - case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */ - pppoe_data_input(netif, p); - break; -#endif /* PPPOE_SUPPORT */ - - default: - ETHARP_STATS_INC(etharp.proterr); - ETHARP_STATS_INC(etharp.drop); - goto free_and_return; - } - - /* This means the pbuf is freed or consumed, - so the caller doesn't have to free it again */ - return ERR_OK; - -free_and_return: - pbuf_free(p); - return ERR_OK; -} -#endif /* LWIP_ARP || LWIP_ETHERNET */