From 6f89409a033ab1b2b66a2fcf214e148f6d3a87d2 Mon Sep 17 00:00:00 2001 From: xjasonlyu Date: Thu, 5 Nov 2020 18:35:45 +0800 Subject: [PATCH] remove v1 --- .github/workflows/docker.yml | 49 - .gitignore | 5 - Dockerfile | 36 - LICENSE | 21 - Makefile | 15 - README.md | 390 -- cmd/main.go | 178 - cmd/main_fakedns.go | 38 - cmd/main_session.go | 28 - common/cache/cache.go | 106 - common/cache/cache_test.go | 70 - common/cache/lrucache.go | 148 - common/cache/lrucache_test.go | 117 - common/domain-trie/node.go | 26 - common/domain-trie/tire.go | 92 - common/domain-trie/trie_test.go | 87 - common/fakeip/pool.go | 107 - common/fakeip/pool_test.go | 51 - common/lsof/lsof.go | 50 - common/lsof/lsof_linux.go | 240 -- common/lsof/lsof_other.go | 7 - common/lsof/lsof_unix.go | 45 - common/lsof/lsof_windows.go | 115 - common/lsof/windows/constants.go | 31 - common/lsof/windows/iphlpapi.go | 102 - common/lsof/windows/kernel32.go | 51 - common/lsof/windows/type.go | 353 -- common/lsof/windows/util.go | 48 - common/packet/packet.go | 59 - common/pool/pool.go | 14 - component/fakedns/fakedns.go | 16 - component/fakedns/middleware.go | 130 - component/fakedns/resolver.go | 133 - component/fakedns/utils.go | 19 - component/session/css/bootstrap.min.css | 7 - component/session/server.go | 221 -- component/session/session.go | 103 - component/session/utils.go | 174 - constant/version.go | 5 - core/addr.go | 46 - core/buffer_pool.go | 35 - core/c/core/altcp.c | 681 ---- core/c/core/altcp_alloc.c | 87 - core/c/core/altcp_tcp.c | 543 --- core/c/core/def.c | 240 -- core/c/core/dns.c | 1631 -------- core/c/core/inet_chksum.c | 608 --- core/c/core/init.c | 380 -- core/c/core/ip.c | 167 - core/c/core/ipv4/autoip.c | 527 --- core/c/core/ipv4/dhcp.c | 1990 ---------- core/c/core/ipv4/etharp.c | 1204 ------ core/c/core/ipv4/icmp.c | 404 -- core/c/core/ipv4/igmp.c | 801 ---- core/c/core/ipv4/ip4.c | 1145 ------ core/c/core/ipv4/ip4_addr.c | 321 -- core/c/core/ipv4/ip4_frag.c | 894 ----- core/c/core/ipv6/dhcp6.c | 812 ---- core/c/core/ipv6/ethip6.c | 123 - core/c/core/ipv6/icmp6.c | 425 -- core/c/core/ipv6/inet6.c | 53 - core/c/core/ipv6/ip6.c | 1505 ------- core/c/core/ipv6/ip6_addr.c | 343 -- core/c/core/ipv6/ip6_frag.c | 862 ---- core/c/core/ipv6/mld6.c | 626 --- core/c/core/ipv6/nd6.c | 2434 ------------ core/c/core/mem.c | 1017 ----- core/c/core/memp.c | 447 --- core/c/core/netif.c | 1795 --------- core/c/core/pbuf.c | 1514 ------- core/c/core/raw.c | 671 ---- core/c/core/stats.c | 169 - core/c/core/sys.c | 148 - core/c/core/tcp.c | 2686 ------------- core/c/core/tcp_in.c | 2194 ---------- core/c/core/tcp_out.c | 2190 ---------- core/c/core/timeouts.c | 451 --- core/c/core/udp.c | 1424 ------- core/c/custom/arch/bpstruct.h | 1 - core/c/custom/arch/cc.h | 6 - core/c/custom/arch/cc_others.h | 99 - core/c/custom/arch/cc_windows.h | 102 - core/c/custom/arch/epstruct.h | 1 - core/c/custom/arch/perf.h | 7 - core/c/custom/arch/sys_arch.h | 7 - core/c/custom/lwipopts.h | 117 - core/c/custom/sys_arch.c | 223 -- core/c/include/compat/posix/arpa/inet.h | 33 - core/c/include/compat/posix/net/if.h | 36 - core/c/include/compat/posix/netdb.h | 33 - core/c/include/compat/posix/sys/socket.h | 33 - core/c/include/compat/stdc/errno.h | 33 - core/c/include/lwip/altcp.h | 201 - core/c/include/lwip/altcp_tcp.h | 72 - core/c/include/lwip/altcp_tls.h | 117 - core/c/include/lwip/api.h | 431 -- core/c/include/lwip/apps/FILES | 2 - core/c/include/lwip/apps/altcp_proxyconnect.h | 79 - .../lwip/apps/altcp_tls_mbedtls_opts.h | 67 - core/c/include/lwip/apps/fs.h | 126 - core/c/include/lwip/apps/http_client.h | 160 - core/c/include/lwip/apps/httpd.h | 255 -- core/c/include/lwip/apps/httpd_opts.h | 396 -- core/c/include/lwip/apps/lwiperf.h | 100 - core/c/include/lwip/apps/mdns.h | 105 - core/c/include/lwip/apps/mdns_opts.h | 81 - core/c/include/lwip/apps/mdns_priv.h | 74 - core/c/include/lwip/apps/mqtt.h | 205 - core/c/include/lwip/apps/mqtt_opts.h | 103 - core/c/include/lwip/apps/mqtt_priv.h | 104 - core/c/include/lwip/apps/netbiosns.h | 51 - core/c/include/lwip/apps/netbiosns_opts.h | 66 - core/c/include/lwip/apps/smtp.h | 128 - core/c/include/lwip/apps/smtp_opts.h | 81 - core/c/include/lwip/apps/snmp.h | 135 - core/c/include/lwip/apps/snmp_core.h | 377 -- core/c/include/lwip/apps/snmp_mib2.h | 78 - core/c/include/lwip/apps/snmp_opts.h | 297 -- core/c/include/lwip/apps/snmp_scalar.h | 113 - .../include/lwip/apps/snmp_snmpv2_framework.h | 32 - core/c/include/lwip/apps/snmp_snmpv2_usm.h | 24 - core/c/include/lwip/apps/snmp_table.h | 134 - core/c/include/lwip/apps/snmp_threadsync.h | 114 - core/c/include/lwip/apps/snmpv3.h | 114 - core/c/include/lwip/apps/sntp.h | 80 - core/c/include/lwip/apps/sntp_opts.h | 209 - core/c/include/lwip/apps/tftp_opts.h | 106 - core/c/include/lwip/apps/tftp_server.h | 95 - core/c/include/lwip/arch.h | 393 -- core/c/include/lwip/autoip.h | 99 - core/c/include/lwip/debug.h | 161 - core/c/include/lwip/def.h | 152 - core/c/include/lwip/dhcp.h | 139 - core/c/include/lwip/dhcp6.h | 104 - core/c/include/lwip/dns.h | 131 - core/c/include/lwip/err.h | 117 - core/c/include/lwip/errno.h | 198 - core/c/include/lwip/etharp.h | 105 - core/c/include/lwip/ethip6.h | 68 - core/c/include/lwip/icmp.h | 110 - core/c/include/lwip/icmp6.h | 72 - core/c/include/lwip/if_api.h | 68 - core/c/include/lwip/igmp.h | 115 - core/c/include/lwip/inet.h | 169 - core/c/include/lwip/inet_chksum.h | 105 - core/c/include/lwip/init.h | 100 - core/c/include/lwip/init.h.cmake.in | 100 - core/c/include/lwip/ip.h | 330 -- core/c/include/lwip/ip4.h | 111 - core/c/include/lwip/ip4_addr.h | 216 - core/c/include/lwip/ip4_frag.h | 100 - core/c/include/lwip/ip6.h | 93 - core/c/include/lwip/ip6_addr.h | 352 -- core/c/include/lwip/ip6_frag.h | 144 - core/c/include/lwip/ip6_zone.h | 304 -- core/c/include/lwip/ip_addr.h | 438 -- core/c/include/lwip/mem.h | 82 - core/c/include/lwip/memp.h | 155 - core/c/include/lwip/mld6.h | 99 - core/c/include/lwip/nd6.h | 90 - core/c/include/lwip/netbuf.h | 116 - core/c/include/lwip/netdb.h | 150 - core/c/include/lwip/netif.h | 669 ---- core/c/include/lwip/netifapi.h | 161 - core/c/include/lwip/opt.h | 3519 ----------------- core/c/include/lwip/pbuf.h | 322 -- core/c/include/lwip/priv/altcp_priv.h | 146 - core/c/include/lwip/priv/api_msg.h | 272 -- core/c/include/lwip/priv/mem_priv.h | 84 - core/c/include/lwip/priv/memp_priv.h | 161 - core/c/include/lwip/priv/memp_std.h | 153 - core/c/include/lwip/priv/nd6_priv.h | 142 - core/c/include/lwip/priv/raw_priv.h | 69 - core/c/include/lwip/priv/sockets_priv.h | 175 - core/c/include/lwip/priv/tcp_priv.h | 523 --- core/c/include/lwip/priv/tcpip_priv.h | 170 - core/c/include/lwip/prot/autoip.h | 78 - core/c/include/lwip/prot/dhcp.h | 178 - core/c/include/lwip/prot/dhcp6.h | 138 - core/c/include/lwip/prot/dns.h | 140 - core/c/include/lwip/prot/etharp.h | 114 - core/c/include/lwip/prot/ethernet.h | 125 - core/c/include/lwip/prot/iana.h | 97 - core/c/include/lwip/prot/icmp.h | 91 - core/c/include/lwip/prot/icmp6.h | 170 - core/c/include/lwip/prot/ieee.h | 91 - core/c/include/lwip/prot/igmp.h | 90 - core/c/include/lwip/prot/ip.h | 59 - core/c/include/lwip/prot/ip4.h | 131 - core/c/include/lwip/prot/ip6.h | 233 -- core/c/include/lwip/prot/mld6.h | 71 - core/c/include/lwip/prot/nd6.h | 274 -- core/c/include/lwip/prot/tcp.h | 100 - core/c/include/lwip/prot/udp.h | 68 - core/c/include/lwip/raw.h | 143 - core/c/include/lwip/sio.h | 142 - core/c/include/lwip/snmp.h | 213 - core/c/include/lwip/sockets.h | 688 ---- core/c/include/lwip/stats.h | 491 --- core/c/include/lwip/sys.h | 560 --- core/c/include/lwip/tcp.h | 502 --- core/c/include/lwip/tcpbase.h | 88 - core/c/include/lwip/tcpip.h | 113 - core/c/include/lwip/timeouts.h | 128 - core/c/include/lwip/udp.h | 232 -- core/c/include/netif/bridgeif.h | 127 - core/c/include/netif/bridgeif_opts.h | 90 - core/c/include/netif/etharp.h | 3 - core/c/include/netif/ethernet.h | 77 - core/c/include/netif/ieee802154.h | 112 - core/c/include/netif/lowpan6.h | 89 - core/c/include/netif/lowpan6_ble.h | 78 - core/c/include/netif/lowpan6_common.h | 82 - core/c/include/netif/lowpan6_opts.h | 122 - core/c/include/netif/ppp/ccp.h | 164 - core/c/include/netif/ppp/chap-md5.h | 36 - core/c/include/netif/ppp/chap-new.h | 200 - core/c/include/netif/ppp/chap_ms.h | 44 - core/c/include/netif/ppp/eap.h | 169 - core/c/include/netif/ppp/ecp.h | 62 - core/c/include/netif/ppp/eui64.h | 102 - core/c/include/netif/ppp/fsm.h | 182 - core/c/include/netif/ppp/ipcp.h | 134 - core/c/include/netif/ppp/ipv6cp.h | 191 - core/c/include/netif/ppp/lcp.h | 179 - core/c/include/netif/ppp/magic.h | 130 - core/c/include/netif/ppp/mppe.h | 181 - core/c/include/netif/ppp/polarssl/arc4.h | 81 - core/c/include/netif/ppp/polarssl/des.h | 92 - core/c/include/netif/ppp/polarssl/md4.h | 97 - core/c/include/netif/ppp/polarssl/md5.h | 96 - core/c/include/netif/ppp/polarssl/sha1.h | 96 - core/c/include/netif/ppp/ppp.h | 698 ---- core/c/include/netif/ppp/ppp_impl.h | 722 ---- core/c/include/netif/ppp/ppp_opts.h | 610 --- core/c/include/netif/ppp/pppapi.h | 137 - core/c/include/netif/ppp/pppcrypt.h | 144 - core/c/include/netif/ppp/pppdebug.h | 88 - core/c/include/netif/ppp/pppoe.h | 187 - core/c/include/netif/ppp/pppol2tp.h | 209 - core/c/include/netif/ppp/pppos.h | 126 - core/c/include/netif/ppp/upap.h | 131 - core/c/include/netif/ppp/vj.h | 169 - core/c/include/netif/slipif.h | 87 - core/c/include/netif/zepif.h | 81 - core/c/include/posix/errno.h | 33 - core/c/include/posix/netdb.h | 33 - core/c/include/posix/sys/socket.h | 33 - core/c_core.go | 22 - core/c_core_4.go | 13 - core/c_core_6.go | 14 - core/c_custom.go | 7 - core/conn.go | 82 - core/core_test.go | 134 - core/errors.go | 60 - core/handler.go | 31 - core/input.go | 127 - core/lwip.go | 170 - core/lwip_other.go | 13 - core/lwip_windows.go | 15 - core/output.go | 46 - core/output_export.go | 28 - core/tcp_callback.go | 62 - core/tcp_callback_export.go | 165 - core/tcp_conn.go | 470 --- core/tcp_conn_map.go | 65 - core/udp_callback.go | 21 - core/udp_callback_export.go | 62 - core/udp_conn.go | 158 - core/udp_conn_map.go | 11 - entrypoint.sh | 43 - filter/filter.go | 10 - filter/icmp.go | 32 - go.mod | 15 - go.sum | 209 - load-tun.sh | 15 - log/level.go | 28 - log/log.go | 82 - proxy/proxy.go | 84 - proxy/socks/socks.go | 247 -- proxy/tcp.go | 126 - proxy/udp.go | 165 - proxy/utils.go | 157 - screenshot.png | Bin 1061953 -> 0 bytes tun/README.md | 1 - tun/stop.go | 34 - tun/tun_darwin.go | 68 - tun/tun_linux.go | 27 - tun/tun_windows.go | 391 -- 289 files changed, 70137 deletions(-) delete mode 100644 .github/workflows/docker.yml delete mode 100644 .gitignore delete mode 100644 Dockerfile delete mode 100644 LICENSE delete mode 100644 Makefile delete mode 100644 README.md delete mode 100644 cmd/main.go delete mode 100644 cmd/main_fakedns.go delete mode 100644 cmd/main_session.go delete mode 100755 common/cache/cache.go delete mode 100755 common/cache/cache_test.go delete mode 100755 common/cache/lrucache.go delete mode 100755 common/cache/lrucache_test.go delete mode 100755 common/domain-trie/node.go delete mode 100755 common/domain-trie/tire.go delete mode 100755 common/domain-trie/trie_test.go delete mode 100755 common/fakeip/pool.go delete mode 100755 common/fakeip/pool_test.go delete mode 100644 common/lsof/lsof.go delete mode 100644 common/lsof/lsof_linux.go delete mode 100644 common/lsof/lsof_other.go delete mode 100644 common/lsof/lsof_unix.go delete mode 100644 common/lsof/lsof_windows.go delete mode 100644 common/lsof/windows/constants.go delete mode 100644 common/lsof/windows/iphlpapi.go delete mode 100644 common/lsof/windows/kernel32.go delete mode 100644 common/lsof/windows/type.go delete mode 100644 common/lsof/windows/util.go delete mode 100644 common/packet/packet.go delete mode 100644 common/pool/pool.go delete mode 100644 component/fakedns/fakedns.go delete mode 100644 component/fakedns/middleware.go delete mode 100644 component/fakedns/resolver.go delete mode 100644 component/fakedns/utils.go delete mode 100644 component/session/css/bootstrap.min.css delete mode 100644 component/session/server.go delete mode 100644 component/session/session.go delete mode 100644 component/session/utils.go delete mode 100644 constant/version.go delete mode 100755 core/addr.go delete mode 100755 core/buffer_pool.go delete mode 100755 core/c/core/altcp.c delete mode 100755 core/c/core/altcp_alloc.c delete mode 100755 core/c/core/altcp_tcp.c delete mode 100755 core/c/core/def.c delete mode 100755 core/c/core/dns.c delete mode 100755 core/c/core/inet_chksum.c delete mode 100755 core/c/core/init.c delete mode 100755 core/c/core/ip.c delete mode 100755 core/c/core/ipv4/autoip.c delete mode 100755 core/c/core/ipv4/dhcp.c delete mode 100755 core/c/core/ipv4/etharp.c delete mode 100755 core/c/core/ipv4/icmp.c delete mode 100755 core/c/core/ipv4/igmp.c delete mode 100755 core/c/core/ipv4/ip4.c delete mode 100755 core/c/core/ipv4/ip4_addr.c delete mode 100755 core/c/core/ipv4/ip4_frag.c delete mode 100755 core/c/core/ipv6/dhcp6.c delete mode 100755 core/c/core/ipv6/ethip6.c delete mode 100755 core/c/core/ipv6/icmp6.c delete mode 100755 core/c/core/ipv6/inet6.c delete mode 100755 core/c/core/ipv6/ip6.c delete mode 100755 core/c/core/ipv6/ip6_addr.c delete mode 100755 core/c/core/ipv6/ip6_frag.c delete mode 100755 core/c/core/ipv6/mld6.c delete mode 100755 core/c/core/ipv6/nd6.c delete mode 100755 core/c/core/mem.c delete mode 100755 core/c/core/memp.c delete mode 100755 core/c/core/netif.c delete mode 100755 core/c/core/pbuf.c delete mode 100755 core/c/core/raw.c delete mode 100755 core/c/core/stats.c delete mode 100755 core/c/core/sys.c delete mode 100755 core/c/core/tcp.c delete mode 100755 core/c/core/tcp_in.c delete mode 100755 core/c/core/tcp_out.c delete mode 100755 core/c/core/timeouts.c delete mode 100755 core/c/core/udp.c delete mode 100755 core/c/custom/arch/bpstruct.h delete mode 100755 core/c/custom/arch/cc.h delete mode 100755 core/c/custom/arch/cc_others.h delete mode 100755 core/c/custom/arch/cc_windows.h delete mode 100755 core/c/custom/arch/epstruct.h delete mode 100755 core/c/custom/arch/perf.h delete mode 100755 core/c/custom/arch/sys_arch.h delete mode 100755 core/c/custom/lwipopts.h delete mode 100755 core/c/custom/sys_arch.c delete mode 100755 core/c/include/compat/posix/arpa/inet.h delete mode 100755 core/c/include/compat/posix/net/if.h delete mode 100755 core/c/include/compat/posix/netdb.h delete mode 100755 core/c/include/compat/posix/sys/socket.h delete mode 100755 core/c/include/compat/stdc/errno.h delete mode 100755 core/c/include/lwip/altcp.h delete mode 100755 core/c/include/lwip/altcp_tcp.h delete mode 100755 core/c/include/lwip/altcp_tls.h delete mode 100755 core/c/include/lwip/api.h delete mode 100755 core/c/include/lwip/apps/FILES delete mode 100755 core/c/include/lwip/apps/altcp_proxyconnect.h delete mode 100755 core/c/include/lwip/apps/altcp_tls_mbedtls_opts.h delete mode 100755 core/c/include/lwip/apps/fs.h delete mode 100755 core/c/include/lwip/apps/http_client.h delete mode 100755 core/c/include/lwip/apps/httpd.h delete mode 100755 core/c/include/lwip/apps/httpd_opts.h delete mode 100755 core/c/include/lwip/apps/lwiperf.h delete mode 100755 core/c/include/lwip/apps/mdns.h delete mode 100755 core/c/include/lwip/apps/mdns_opts.h delete mode 100755 core/c/include/lwip/apps/mdns_priv.h delete mode 100755 core/c/include/lwip/apps/mqtt.h delete mode 100755 core/c/include/lwip/apps/mqtt_opts.h delete mode 100755 core/c/include/lwip/apps/mqtt_priv.h delete mode 100755 core/c/include/lwip/apps/netbiosns.h delete mode 100755 core/c/include/lwip/apps/netbiosns_opts.h delete mode 100755 core/c/include/lwip/apps/smtp.h delete mode 100755 core/c/include/lwip/apps/smtp_opts.h delete mode 100755 core/c/include/lwip/apps/snmp.h delete mode 100755 core/c/include/lwip/apps/snmp_core.h delete mode 100755 core/c/include/lwip/apps/snmp_mib2.h delete mode 100755 core/c/include/lwip/apps/snmp_opts.h delete mode 100755 core/c/include/lwip/apps/snmp_scalar.h delete mode 100755 core/c/include/lwip/apps/snmp_snmpv2_framework.h delete mode 100755 core/c/include/lwip/apps/snmp_snmpv2_usm.h delete mode 100755 core/c/include/lwip/apps/snmp_table.h delete mode 100755 core/c/include/lwip/apps/snmp_threadsync.h delete mode 100755 core/c/include/lwip/apps/snmpv3.h delete mode 100755 core/c/include/lwip/apps/sntp.h delete mode 100755 core/c/include/lwip/apps/sntp_opts.h delete mode 100755 core/c/include/lwip/apps/tftp_opts.h delete mode 100755 core/c/include/lwip/apps/tftp_server.h delete mode 100755 core/c/include/lwip/arch.h delete mode 100755 core/c/include/lwip/autoip.h delete mode 100755 core/c/include/lwip/debug.h delete mode 100755 core/c/include/lwip/def.h delete mode 100755 core/c/include/lwip/dhcp.h delete mode 100755 core/c/include/lwip/dhcp6.h delete mode 100755 core/c/include/lwip/dns.h delete mode 100755 core/c/include/lwip/err.h delete mode 100755 core/c/include/lwip/errno.h delete mode 100755 core/c/include/lwip/etharp.h delete mode 100755 core/c/include/lwip/ethip6.h delete mode 100755 core/c/include/lwip/icmp.h delete mode 100755 core/c/include/lwip/icmp6.h delete mode 100755 core/c/include/lwip/if_api.h delete mode 100755 core/c/include/lwip/igmp.h delete mode 100755 core/c/include/lwip/inet.h delete mode 100755 core/c/include/lwip/inet_chksum.h delete mode 100755 core/c/include/lwip/init.h delete mode 100755 core/c/include/lwip/init.h.cmake.in delete mode 100755 core/c/include/lwip/ip.h delete mode 100755 core/c/include/lwip/ip4.h delete mode 100755 core/c/include/lwip/ip4_addr.h delete mode 100755 core/c/include/lwip/ip4_frag.h delete mode 100755 core/c/include/lwip/ip6.h delete mode 100755 core/c/include/lwip/ip6_addr.h delete mode 100755 core/c/include/lwip/ip6_frag.h delete mode 100755 core/c/include/lwip/ip6_zone.h delete mode 100755 core/c/include/lwip/ip_addr.h delete mode 100755 core/c/include/lwip/mem.h delete mode 100755 core/c/include/lwip/memp.h delete mode 100755 core/c/include/lwip/mld6.h delete mode 100755 core/c/include/lwip/nd6.h delete mode 100755 core/c/include/lwip/netbuf.h delete mode 100755 core/c/include/lwip/netdb.h delete mode 100755 core/c/include/lwip/netif.h delete mode 100755 core/c/include/lwip/netifapi.h delete mode 100755 core/c/include/lwip/opt.h delete mode 100755 core/c/include/lwip/pbuf.h delete mode 100755 core/c/include/lwip/priv/altcp_priv.h delete mode 100755 core/c/include/lwip/priv/api_msg.h delete mode 100755 core/c/include/lwip/priv/mem_priv.h delete mode 100755 core/c/include/lwip/priv/memp_priv.h delete mode 100755 core/c/include/lwip/priv/memp_std.h delete mode 100755 core/c/include/lwip/priv/nd6_priv.h delete mode 100755 core/c/include/lwip/priv/raw_priv.h delete mode 100755 core/c/include/lwip/priv/sockets_priv.h delete mode 100755 core/c/include/lwip/priv/tcp_priv.h delete mode 100755 core/c/include/lwip/priv/tcpip_priv.h delete mode 100755 core/c/include/lwip/prot/autoip.h delete mode 100755 core/c/include/lwip/prot/dhcp.h delete mode 100755 core/c/include/lwip/prot/dhcp6.h delete mode 100755 core/c/include/lwip/prot/dns.h delete mode 100755 core/c/include/lwip/prot/etharp.h delete mode 100755 core/c/include/lwip/prot/ethernet.h delete mode 100755 core/c/include/lwip/prot/iana.h delete mode 100755 core/c/include/lwip/prot/icmp.h delete mode 100755 core/c/include/lwip/prot/icmp6.h delete mode 100755 core/c/include/lwip/prot/ieee.h delete mode 100755 core/c/include/lwip/prot/igmp.h delete mode 100755 core/c/include/lwip/prot/ip.h delete mode 100755 core/c/include/lwip/prot/ip4.h delete mode 100755 core/c/include/lwip/prot/ip6.h delete mode 100755 core/c/include/lwip/prot/mld6.h delete mode 100755 core/c/include/lwip/prot/nd6.h delete mode 100755 core/c/include/lwip/prot/tcp.h delete mode 100755 core/c/include/lwip/prot/udp.h delete mode 100755 core/c/include/lwip/raw.h delete mode 100755 core/c/include/lwip/sio.h delete mode 100755 core/c/include/lwip/snmp.h delete mode 100755 core/c/include/lwip/sockets.h delete mode 100755 core/c/include/lwip/stats.h delete mode 100755 core/c/include/lwip/sys.h delete mode 100755 core/c/include/lwip/tcp.h delete mode 100755 core/c/include/lwip/tcpbase.h delete mode 100755 core/c/include/lwip/tcpip.h delete mode 100755 core/c/include/lwip/timeouts.h delete mode 100755 core/c/include/lwip/udp.h delete mode 100755 core/c/include/netif/bridgeif.h delete mode 100755 core/c/include/netif/bridgeif_opts.h delete mode 100755 core/c/include/netif/etharp.h delete mode 100755 core/c/include/netif/ethernet.h delete mode 100755 core/c/include/netif/ieee802154.h delete mode 100755 core/c/include/netif/lowpan6.h delete mode 100755 core/c/include/netif/lowpan6_ble.h delete mode 100755 core/c/include/netif/lowpan6_common.h delete mode 100755 core/c/include/netif/lowpan6_opts.h delete mode 100755 core/c/include/netif/ppp/ccp.h delete mode 100755 core/c/include/netif/ppp/chap-md5.h delete mode 100755 core/c/include/netif/ppp/chap-new.h delete mode 100755 core/c/include/netif/ppp/chap_ms.h delete mode 100755 core/c/include/netif/ppp/eap.h delete mode 100755 core/c/include/netif/ppp/ecp.h delete mode 100755 core/c/include/netif/ppp/eui64.h delete mode 100755 core/c/include/netif/ppp/fsm.h delete mode 100755 core/c/include/netif/ppp/ipcp.h delete mode 100755 core/c/include/netif/ppp/ipv6cp.h delete mode 100755 core/c/include/netif/ppp/lcp.h delete mode 100755 core/c/include/netif/ppp/magic.h delete mode 100755 core/c/include/netif/ppp/mppe.h delete mode 100755 core/c/include/netif/ppp/polarssl/arc4.h delete mode 100755 core/c/include/netif/ppp/polarssl/des.h delete mode 100755 core/c/include/netif/ppp/polarssl/md4.h delete mode 100755 core/c/include/netif/ppp/polarssl/md5.h delete mode 100755 core/c/include/netif/ppp/polarssl/sha1.h delete mode 100755 core/c/include/netif/ppp/ppp.h delete mode 100755 core/c/include/netif/ppp/ppp_impl.h delete mode 100755 core/c/include/netif/ppp/ppp_opts.h delete mode 100755 core/c/include/netif/ppp/pppapi.h delete mode 100755 core/c/include/netif/ppp/pppcrypt.h delete mode 100755 core/c/include/netif/ppp/pppdebug.h delete mode 100755 core/c/include/netif/ppp/pppoe.h delete mode 100755 core/c/include/netif/ppp/pppol2tp.h delete mode 100755 core/c/include/netif/ppp/pppos.h delete mode 100755 core/c/include/netif/ppp/upap.h delete mode 100755 core/c/include/netif/ppp/vj.h delete mode 100755 core/c/include/netif/slipif.h delete mode 100755 core/c/include/netif/zepif.h delete mode 100755 core/c/include/posix/errno.h delete mode 100755 core/c/include/posix/netdb.h delete mode 100755 core/c/include/posix/sys/socket.h delete mode 100755 core/c_core.go delete mode 100755 core/c_core_4.go delete mode 100755 core/c_core_6.go delete mode 100755 core/c_custom.go delete mode 100755 core/conn.go delete mode 100755 core/core_test.go delete mode 100755 core/errors.go delete mode 100755 core/handler.go delete mode 100755 core/input.go delete mode 100755 core/lwip.go delete mode 100755 core/lwip_other.go delete mode 100755 core/lwip_windows.go delete mode 100755 core/output.go delete mode 100755 core/output_export.go delete mode 100755 core/tcp_callback.go delete mode 100755 core/tcp_callback_export.go delete mode 100755 core/tcp_conn.go delete mode 100755 core/tcp_conn_map.go delete mode 100755 core/udp_callback.go delete mode 100755 core/udp_callback_export.go delete mode 100755 core/udp_conn.go delete mode 100755 core/udp_conn_map.go delete mode 100644 entrypoint.sh delete mode 100644 filter/filter.go delete mode 100644 filter/icmp.go delete mode 100644 go.mod delete mode 100644 go.sum delete mode 100644 load-tun.sh delete mode 100644 log/level.go delete mode 100644 log/log.go delete mode 100644 proxy/proxy.go delete mode 100755 proxy/socks/socks.go delete mode 100644 proxy/tcp.go delete mode 100644 proxy/udp.go delete mode 100644 proxy/utils.go delete mode 100644 screenshot.png delete mode 100644 tun/README.md delete mode 100644 tun/stop.go delete mode 100644 tun/tun_darwin.go delete mode 100644 tun/tun_linux.go delete mode 100644 tun/tun_windows.go diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml deleted file mode 100644 index e92179b..0000000 --- a/.github/workflows/docker.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Publish Docker Image - -on: - push: - branches: - - master - paths-ignore: - - '.github/**' - - '.gitignore' - - 'README.md' - -jobs: - - build: - name: Build - runs-on: ubuntu-latest - steps: - - - name: Check out code into the Go module directory - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Get Version - id: shell - run: | - echo ::set-output name=version::$(git describe --tags --long | cut -c 2-) - - - name: Build and Push - if: github.ref == 'refs/heads/master' - uses: docker/build-push-action@v2 - with: - push: true - platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64 - tags: | - xjasonlyu/tun2socks:latest - xjasonlyu/tun2socks:${{ steps.shell.outputs.version }} diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 8bdad86..0000000 --- a/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ - -.idea/ -.DS_Store - -bin/ diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 90f71ba..0000000 --- a/Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -FROM golang:alpine as builder - -WORKDIR /tun2socks-src -COPY . /tun2socks-src - -RUN apk add --update --no-cache \ - gcc git make musl-dev \ - && go get -u -d ./... \ - && go get -u github.com/gobuffalo/packr/v2/packr2 \ - && make \ - && /tun2socks-src/bin/tun2socks -version - -FROM alpine:latest - -COPY ./entrypoint.sh / -COPY --from=builder /tun2socks-src/bin/tun2socks /tun2socks - -RUN apk add --update --no-cache iptables iproute2 \ - && chmod +x /entrypoint.sh - -ENV TUN tun0 -ENV ETH eth0 -ENV ETH_ADDR= -ENV TUN_ADDR= -ENV TUN_MASK= -ENV PROXY= -ENV LOGLEVEL= -ENV EXCLUDED= -ENV EXTRACMD= -ENV MONITOR= -ENV MONITOR_ADDR= -ENV FAKEDNS= -ENV BACKEND_DNS= -ENV HOSTS= - -ENTRYPOINT ["/entrypoint.sh"] diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 5b8eed3..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 X. Jason Lyu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/Makefile b/Makefile deleted file mode 100644 index 7a65330..0000000 --- a/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -NAME=tun2socks -BINDIR=$(shell pwd)/bin -VERSION=$(shell git describe --tags --long || echo "unknown version") -BUILDTAGS='fakedns session' -GOBUILD=go build -trimpath -ldflags '-s -w -extldflags "-static" -X "github.com/xjasonlyu/tun2socks/constant.Version=$(VERSION)"' - -all: build - -build: - cd component/session && packr2 - cd cmd && $(GOBUILD) -v -tags $(BUILDTAGS) -o $(BINDIR)/$(NAME) - cd component/session && packr2 clean - -clean: - rm -rf $(BINDIR) diff --git a/README.md b/README.md deleted file mode 100644 index d327609..0000000 --- a/README.md +++ /dev/null @@ -1,390 +0,0 @@ -# tun2socks - -A tun2socks implementation written in Go. - -forked & modified from [eycorsican/go-tun2socks](https://github.com/eycorsican/go-tun2socks) - -## Preview - -Tun2socks status web view (`-monitor` option is required) -![status](./screenshot.png) - -## What's the difference with the original project - -- Add new features (listed below) -- Optimize handlers (e.g. new TCP/UDP proxy handler) -- Rewrite and remove some implementations - -## Main Features - -Previous Features - -- TCP and UDP support -- IPv4 gateway support -- Support proxy handler: `SOCKS5` -- ICMP echoing - -New Features - -- Fake DNS (Fake IP range: `198.18.0.0/15`) -- Backend DNS (resolve non-TypeA query) -- Hijack DNS (force the specific DNS to get a fake address) -- Hosts mapping (e.g. `localhost`->`127.0.0.1`) -- Web statistics monitor - -## How to Build - -`go-tun2socks` is using `cgo` and `go modules`, thus a C compiler and GO version >= 1.13 are required. - -```sh -git clone https://github.com/xjasonlyu/tun2socks.git -cd tun2socks && go mod download -make clean && make build -./bin/tun2socks -h -``` - -Or build via Docker - -```sh -docker build -t tun2socks . -``` - -## Running in Docker (My Daily Workaround) - -Create a `macvlan` network called `switch` - -```sh -docker network create -d macvlan \ - --subnet=10.0.0.0/24 \ - --gateway=10.0.0.1 \ - -o parent=eth0 \ - switch -``` - -Pull `tun2socks` docker image - -```sh -docker pull xjasonlyu/tun2socks -``` - -Run `tun2socks` as a gateway (e.g. 10.0.0.2) - -```sh -docker run -d \ - --network switch \ - --name tun2socks \ - --ip 10.0.0.2 \ - --privileged \ - --restart always \ - --sysctl net.ipv4.ip_forward=1 \ - xjasonlyu/tun2socks -``` - -PS: - -- Works on Synology NAS -- Add custom environment variables if needed - -## Alpine VM Demo - -This project is running on my server as a second gateway, so my Apple TV and other devices could access the full internet and AD block function without complex configuration. - -Here is my Running Environment - -- Linux alpine 4.19.79-0-virt (VM) -- Proxy Server: 10.0.0.3 -- Alpine Address: 10.0.0.2 -- Router Gateway: 10.0.0.1 -- Apple TV Address: 10.0.0.120 - -
- This is my alpine tun2socks service file - -```sh -#!/sbin/openrc-run - -### tun2socks options -TUN="utun0" -ETH="eth0" -ETHGW="10.0.0.1" -TUNGW="240.0.0.1" -SOCKS="10.0.0.3:1080" -MONITOR="0.0.0.0:80" -HIJACKDNS="" -BACKENDDNS="1.2.4.8:53,1.1.1.1:53" -HOSTS="localhost=127.0.0.1" -OPTIONS="-loglevel warning -tunName $TUN -proxyServer $SOCKS -monitor -monitorAddr $MONITOR -fakeDNS -hosts $HOSTS -backendDNS $BACKENDDNS" - -### openrc options -description="the tun2socks route process" -name=$RC_SVCNAME -pidfile="/var/run/$RC_SVCNAME.pid" -logfile="/var/log/$RC_SVCNAME.log" -command="/usr/local/bin/tun2socks" -command_args=$OPTIONS -command_user="root" -command_background="yes" - -depend() { - #after * - before chronyd - after firewall - use dns -} - -_set_dns() { - option=$1 - case $option in - 0) - einfo "DNS settings updated" - [ -f /etc/resolv.conf.copy ] || mv /etc/resolv.conf /etc/resolv.conf.copy - cat > /etc/resolv.conf << EOF -nameserver $TUNGW -EOF - ;; - 1) - einfo "DNS settings restored" - cp -f /etc/resolv.conf.copy /etc/resolv.conf - ;; - *) - return 0 - ;; - esac - eend $? -} - -start_pre() { - if [ "${RC_CMD}" = "restart" ]; then - ip link delete $TUN 2> /dev/null - fi - - # enable ip_forward - einfo $(sysctl -w net.ipv4.ip_forward=1) && eend $? - - # create tun device - ip tuntap add mode tun dev $TUN - ip addr add $TUNGW/24 dev $TUN - ip link set dev $TUN up - einfo "tun device created: $TUN" && eend $? - - # change default gateway - ip route del default 2> /dev/null - ip route add default via $TUNGW dev $TUN - - # add to ip route - #ip route add 1.1.1.1/32 via $ETHGW - - # DNS settings - _set_dns 0 -} - -stop_post() { - # disable ip_forward - einfo $(sysctl -w net.ipv4.ip_forward=0) && eend $? - - # delete from ip route - #ip route del 1.1.1.1/32 via $ETHGW - - # change default gateway - # ip route del default - ip route add default via $ETHGW dev $ETH 2> /dev/null - - # delete tun device - #ip link set dev $TUN down - #ip addr del $TUNGW/24 dev $TUN - #ip tuntap del mode tun dev $TUN - ip link delete $TUN 2> /dev/null - einfo "tun device deleted: $TUN" && eend $? - - # DNS settings - _set_dns 1 -} - -start() { - ebegin "Starting $RC_SVCNAME" - start-stop-daemon --start --quiet \ - --background --exec $command \ - --user $command_user \ - --make-pidfile --pidfile $pidfile \ - --stdout $logfile --stderr $logfile \ - -- $command_args - eend $? -} - -stop() { - if [ "${RC_CMD}" = "restart" ]; then - _pid=$(pgrep $RC_SVCNAME) - if [ "$_pid" != "$(cat $pidfile)" ]; then - echo $_pid > $pidfile - fi - fi - - ebegin "Stopping $RC_SVCNAME" - start-stop-daemon --stop --quiet --exec "$command" \ - --pidfile "$pidfile" - eend $? - - if [ "$RC_RUNLEVEL" = "shutdown" ]; then - _pid=$(pgrep $RC_SVCNAME) - if [ -n $_pid ]; then - kill -9 $_pid > /dev/null 2>&1 - fi - rm -rf $pidfile - fi -} -``` - -
- -Follow 3 Steps - -- Simply put this config in `/etc/init.d/` -- Give it executable permission `chmod +x tun2socks` -- Launch the service `rc-service tun2socks start` - -Finally, all you need to do is modify your internet settings. - -In this case, I just need configure my Apple TV internet settings from DHCP to Static, and change my gateway and DNS to `10.0.0.2`. - -Done! - -## Tun2socks Usage - -```text -Usage of tun2socks: - -backendDNS string - Backend DNS to resolve non-TypeA or non-ClassINET query (must support tcp) (default "8.8.8.8:53,8.8.4.4:53") - -fakeDNS - Enable fake DNS - -fakeDNSAddr string - Listen address of fake DNS (default ":53") - -hijackDNS string - Hijack the specific DNS query to get a fake ip, e.g. '*:53', '8.8.8.8:53,8.8.4.4:53' - -hosts string - DNS hosts mapping, e.g. 'example.com=1.1.1.1,example.net=2.2.2.2' - -loglevel string - Logging level [info, warning, error, debug, silent] (default "info") - -monitor - Enable session statistics monitor - -monitorAddr string - Listen address of session monitor, open in your browser to view statistics (default "localhost:6001") - -proxyServer string - Proxy server address - -tunAddr string - TUN interface address (default "240.0.0.2") - -tunDNS string - DNS resolvers for TUN interface (Windows Only) (default "8.8.8.8,8.8.4.4") - -tunGw string - TUN interface gateway (default "240.0.0.1") - -tunMask string - TUN interface netmask (default "255.255.255.0") - -tunName string - TUN interface name (default "utun0") - -tunPersist - Persist TUN interface after the program exits or the last open file descriptor is closed (Linux only) - -udpTimeout duration - UDP session timeout (default 30s) - -version - Show current version of tun2socks -``` - -## Run - -```sh -tun2socks -loglevel warning -tunName utun0 -proxyServer 1.2.3.4:1080 -monitor -monitorAddr 0.0.0.0:80 -fakeDNS -hosts localhost=127.0.0.1 -backendDNS 1.1.1.1:53,8.8.8.8:53 -``` - -Note that the TUN device may have a different name, and it should be a different name on Windows unless you have renamed it, so make sure use `ifconfig`, `ipconfig` or `ip addr` to check it out. - -## Create TUN device and Configure Routing Table - -Suppose your original gateway is 192.168.0.1. The proxy server address is 1.2.3.4. - -The following commands will need root permissions. - -### macOS - -The program will automatically create a TUN device for you on macOS. To show the created TUN device, use `ifconfig`. - -Delete original gateway: - -```sh -route delete default -``` - -Add our TUN interface as the default gateway: - -```sh -route add default 240.0.0.1 -``` - -Add a route for your proxy server to bypass the TUN interface: - -```sh -route add 1.2.3.4/32 192.168.0.1 -``` - -### Linux - -The program will not create the TUN device for you on Linux. You need to create the TUN device by yourself: - -```sh -ip tuntap add mode tun dev tun1 -ip addr add 240.0.0.1 dev tun1 -ip link set dev tun1 up -``` - -Delete original gateway: - -```sh -ip route del default -``` - -Add our TUN interface as the default gateway: - -```sh -ip route add default via 240.0.0.1 -``` - -Add a route for your proxy server to bypass the TUN interface: - -```sh -ip route add 1.2.3.4/32 via 192.168.0.1 -``` - -### Windows - -[使用教程](https://medium.com/@TachyonDevel/%E6%95%99%E7%A8%8B-%E5%9C%A8-windows-%E4%B8%8A%E4%BD%BF%E7%94%A8-tun2socks-%E8%BF%9B%E8%A1%8C%E5%85%A8%E5%B1%80%E4%BB%A3%E7%90%86-aa51869dd0d) - Tutorial in Chinese - -To create a TUN device on Windows, you need [Tap-windows](http://build.openvpn.net/downloads/releases/), refer [here](https://code.google.com/archive/p/badvpn/wikis/tun2socks.wiki) for more information. - -Add our TUN interface as the default gateway: - -```sh -# Using 240.0.0.1 is not allowed on Windows, we use 10.0.0.1 instead -route add 0.0.0.0 mask 0.0.0.0 10.0.0.1 metric 6 -``` - -Add a route for your proxy server to bypass the TUN interface: - -```sh -route add 1.2.3.4 192.168.0.1 metric 5 -``` - -## This project is using lwIP - -This project is using a modified version of lwIP, you can checkout this repo to find out what are the changes: https://github.com/eycorsican/lwip (original author) - -## Many thanks to the following projects - -- https://savannah.nongnu.org/projects/lwip -- https://github.com/ambrop72/badvpn -- https://github.com/zhuhaow/tun2socks -- https://github.com/yinghuocho/gotun2socks -- https://github.com/v2ray/v2ray-core -- https://github.com/shadowsocks/go-shadowsocks2 -- https://github.com/Dreamacro/clash -- https://github.com/songgao/water -- https://github.com/nadoo/glider -- https://github.com/miekg/dns -- https://github.com/sirupsen/logrus diff --git a/cmd/main.go b/cmd/main.go deleted file mode 100644 index 03d57ae..0000000 --- a/cmd/main.go +++ /dev/null @@ -1,178 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "io" - "net" - "os" - "os/signal" - "runtime" - "strings" - "syscall" - "time" - - C "github.com/xjasonlyu/tun2socks/constant" - "github.com/xjasonlyu/tun2socks/core" - "github.com/xjasonlyu/tun2socks/filter" - "github.com/xjasonlyu/tun2socks/log" - "github.com/xjasonlyu/tun2socks/proxy" - "github.com/xjasonlyu/tun2socks/tun" - - D "github.com/xjasonlyu/tun2socks/component/fakedns" - S "github.com/xjasonlyu/tun2socks/component/session" -) - -const MTU = 1500 - -var ( - args = new(CmdArgs) - - // Modules init func - registeredInitFn []func() - - fakeDNS D.FakeDNS - monitor S.Monitor -) - -type CmdArgs struct { - // Main - Version *bool - TunName *string - TunAddr *string - TunGw *string - TunMask *string - TunDNS *string - TunPersist *bool - LogLevel *string - - // Proxy - ProxyServer *string - UdpTimeout *time.Duration - - // FakeDNS - EnableFakeDNS *bool - FakeDNSAddr *string - Hosts *string - HijackDNS *string - BackendDNS *string - - // Session Monitor - EnableMonitor *bool - MonitorAddr *string -} - -func registerInitFn(fn func()) { - registeredInitFn = append(registeredInitFn, fn) -} - -func init() { - // Main - args.Version = flag.Bool("version", false, "Show current version of tun2socks") - args.LogLevel = flag.String("loglevel", "info", "Logging level [info, warning, error, debug, silent]") - args.TunName = flag.String("tunName", "utun0", "TUN interface name") - args.TunAddr = flag.String("tunAddr", "240.0.0.2", "TUN interface address") - args.TunGw = flag.String("tunGw", "240.0.0.1", "TUN interface gateway") - args.TunMask = flag.String("tunMask", "255.255.255.0", "TUN interface netmask") - args.TunDNS = flag.String("tunDNS", "8.8.8.8,8.8.4.4", "DNS resolvers for TUN interface (Windows Only)") - args.TunPersist = flag.Bool("tunPersist", false, "Persist TUN interface after the program exits or the last open file descriptor is closed (Linux only)") - - // Proxy - args.ProxyServer = flag.String("proxyServer", "", "Proxy server address") - args.UdpTimeout = flag.Duration("udpTimeout", 30*time.Second, "UDP session timeout") -} - -func showVersion() { - version := strings.Split(C.Version[1:], "-") - fmt.Printf("Go-tun2socks %s (%s)\n", version[0], version[1]) - fmt.Printf("%s/%s, %s, %s\n", runtime.GOOS, runtime.GOARCH, runtime.Version(), version[2]) -} - -func main() { - // Parse arguments - flag.Parse() - - if *args.Version { - showVersion() - os.Exit(0) - } - - // Set log level - switch strings.ToLower(*args.LogLevel) { - case "debug": - log.SetLevel(log.DEBUG) - case "info": - log.SetLevel(log.INFO) - case "warning": - log.SetLevel(log.WARNING) - case "error": - log.SetLevel(log.ERROR) - case "silent": - log.SetLevel(log.SILENT) - default: - panic("unsupported logging level") - } - - // Initialization modules - for _, fn := range registeredInitFn { - if fn != nil { - fn() - } - } - - // Resolve proxy address - proxyAddr, err := net.ResolveTCPAddr("tcp", *args.ProxyServer) - if err != nil { - log.Fatalf("invalid proxy server address: %v", err) - } - proxyHost := proxyAddr.IP.String() - proxyPort := proxyAddr.Port - - // Open the tun device - dnsServers := strings.Split(*args.TunDNS, ",") - tunDev, err := tun.OpenTunDevice(*args.TunName, *args.TunAddr, *args.TunGw, *args.TunMask, dnsServers, *args.TunPersist) - if err != nil { - log.Fatalf("failed to open tun device: %v", err) - } - - // Setup TCP/IP stack - var lwipWriter = core.NewLWIPStack().(io.Writer) - // Wrap a writer to delay ICMP packets - lwipWriter = filter.NewICMPFilter(lwipWriter).(io.Writer) - - // Register modules to proxy - proxy.RegisterMonitor(monitor) - proxy.RegisterFakeDNS(fakeDNS, *args.HijackDNS) - // Register TCP and UDP handlers to handle accepted connections. - core.RegisterTCPConnHandler(proxy.NewTCPHandler(proxyHost, proxyPort)) - core.RegisterUDPConnHandler(proxy.NewUDPHandler(proxyHost, proxyPort, *args.UdpTimeout)) - - // Register an output callback to write packets output from lwip stack to tun - // device, output function should be set before input any packets. - core.RegisterOutputFn(func(data []byte) (int, error) { - return tunDev.Write(data) - }) - - // Copy packets from tun device to lwip stack, it's the main loop. - go func() { - if _, err := io.CopyBuffer(lwipWriter, tunDev, make([]byte, MTU)); err != nil { - log.Fatalf("copying data failed: %v", err) - } - }() - - log.Infof("Running Go-tun2socks") - - osSignals := make(chan os.Signal, 1) - signal.Notify(osSignals, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGHUP) - <-osSignals - - // Stop fakeDNS - if fakeDNS != nil { - fakeDNS.Stop() - } - - // Stop session monitor - if monitor != nil { - monitor.Stop() - } -} diff --git a/cmd/main_fakedns.go b/cmd/main_fakedns.go deleted file mode 100644 index b0c2fb4..0000000 --- a/cmd/main_fakedns.go +++ /dev/null @@ -1,38 +0,0 @@ -// +build fakedns - -package main - -import ( - "flag" - - "github.com/xjasonlyu/tun2socks/component/fakedns" - "github.com/xjasonlyu/tun2socks/log" -) - -func init() { - args.EnableFakeDNS = flag.Bool("fakeDNS", false, "Enable fake DNS") - args.FakeDNSAddr = flag.String("fakeDNSAddr", ":53", "Listen address of fake DNS") - args.Hosts = flag.String("hosts", "", "DNS hosts mapping, e.g. 'example.com=1.1.1.1,example.net=2.2.2.2'") - args.HijackDNS = flag.String("hijackDNS", "", "Hijack the specific DNS query to get a fake ip, e.g. '*:53', '8.8.8.8:53,8.8.4.4:53'") - args.BackendDNS = flag.String("backendDNS", "8.8.8.8:53,8.8.4.4:53", "Backend DNS to resolve !TypeA or !ClassINET query (must support tcp)") - - registerInitFn(func() { - if *args.EnableFakeDNS { - var err error - fakeDNS, err = fakedns.NewResolver(*args.FakeDNSAddr, *args.Hosts) - if err != nil { - log.Fatalf("Create fake DNS server failed: %v", err) - } - - // Register backend DNS - fakedns.RegisterDNS(*args.BackendDNS) - - // Start FakeDNS - if err := fakeDNS.Start(); err != nil { - log.Fatalf("Start fake DNS failed: %v", err) - } - } else { - fakeDNS = nil - } - }) -} diff --git a/cmd/main_session.go b/cmd/main_session.go deleted file mode 100644 index b068145..0000000 --- a/cmd/main_session.go +++ /dev/null @@ -1,28 +0,0 @@ -// +build session - -package main - -import ( - "flag" - - "github.com/xjasonlyu/tun2socks/component/session" - "github.com/xjasonlyu/tun2socks/log" -) - -func init() { - args.EnableMonitor = flag.Bool("monitor", false, "Enable session statistics monitor") - args.MonitorAddr = flag.String("monitorAddr", "localhost:6001", "Listen address of session monitor, open in your browser to view statistics") - - registerInitFn(func() { - if *args.EnableMonitor { - monitor = session.New(*args.MonitorAddr) - - // Start session monitor - if err := monitor.Start(); err != nil { - log.Fatalf("Start session monitor failed: %v", err) - } - } else { - monitor = nil - } - }) -} diff --git a/common/cache/cache.go b/common/cache/cache.go deleted file mode 100755 index 6b252c2..0000000 --- a/common/cache/cache.go +++ /dev/null @@ -1,106 +0,0 @@ -package cache - -import ( - "runtime" - "sync" - "time" -) - -// Cache store element with a expired time -type Cache struct { - *cache -} - -type cache struct { - mapping sync.Map - janitor *janitor -} - -type element struct { - Expired time.Time - Payload interface{} -} - -// Put element in Cache with its ttl -func (c *cache) Put(key interface{}, payload interface{}, ttl time.Duration) { - c.mapping.Store(key, &element{ - Payload: payload, - Expired: time.Now().Add(ttl), - }) -} - -// Get element in Cache, and drop when it expired -func (c *cache) Get(key interface{}) interface{} { - item, exist := c.mapping.Load(key) - if !exist { - return nil - } - elm := item.(*element) - // expired - if time.Since(elm.Expired) > 0 { - c.mapping.Delete(key) - return nil - } - return elm.Payload -} - -// GetWithExpire element in Cache with Expire Time -func (c *cache) GetWithExpire(key interface{}) (payload interface{}, expired time.Time) { - item, exist := c.mapping.Load(key) - if !exist { - return - } - elm := item.(*element) - // expired - if time.Since(elm.Expired) > 0 { - c.mapping.Delete(key) - return - } - return elm.Payload, elm.Expired -} - -func (c *cache) cleanup() { - c.mapping.Range(func(k, v interface{}) bool { - key := k.(string) - elm := v.(*element) - if time.Since(elm.Expired) > 0 { - c.mapping.Delete(key) - } - return true - }) -} - -type janitor struct { - interval time.Duration - stop chan struct{} -} - -func (j *janitor) process(c *cache) { - ticker := time.NewTicker(j.interval) - for { - select { - case <-ticker.C: - c.cleanup() - case <-j.stop: - ticker.Stop() - return - } - } -} - -func stopJanitor(c *Cache) { - c.janitor.stop <- struct{}{} -} - -// New return *Cache -func New(interval time.Duration) *Cache { - j := &janitor{ - interval: interval, - stop: make(chan struct{}), - } - c := &cache{janitor: j} - go j.process(c) - C := &Cache{c} - runtime.SetFinalizer(C, stopJanitor) - return C -} diff --git a/common/cache/cache_test.go b/common/cache/cache_test.go deleted file mode 100755 index cf4a391..0000000 --- a/common/cache/cache_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package cache - -import ( - "runtime" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestCache_Basic(t *testing.T) { - interval := 200 * time.Millisecond - ttl := 20 * time.Millisecond - c := New(interval) - c.Put("int", 1, ttl) - c.Put("string", "a", ttl) - - i := c.Get("int") - assert.Equal(t, i.(int), 1, "should recv 1") - - s := c.Get("string") - assert.Equal(t, s.(string), "a", "should recv 'a'") -} - -func TestCache_TTL(t *testing.T) { - interval := 200 * time.Millisecond - ttl := 20 * time.Millisecond - now := time.Now() - c := New(interval) - c.Put("int", 1, ttl) - c.Put("int2", 2, ttl) - - i := c.Get("int") - _, expired := c.GetWithExpire("int2") - assert.Equal(t, i.(int), 1, "should recv 1") - assert.True(t, now.Before(expired)) - - time.Sleep(ttl * 2) - i = c.Get("int") - j, _ := c.GetWithExpire("int2") - assert.Nil(t, i, "should recv nil") - assert.Nil(t, j, "should recv nil") -} - -func TestCache_AutoCleanup(t *testing.T) { - interval := 10 * time.Millisecond - ttl := 15 * time.Millisecond - c := New(interval) - c.Put("int", 1, ttl) - - time.Sleep(ttl * 2) - i := c.Get("int") - j, _ := c.GetWithExpire("int") - assert.Nil(t, i, "should recv nil") - assert.Nil(t, j, "should recv nil") -} - -func TestCache_AutoGC(t *testing.T) { - sign := make(chan struct{}) - go func() { - interval := 10 * time.Millisecond - ttl := 15 * time.Millisecond - c := New(interval) - c.Put("int", 1, ttl) - sign <- struct{}{} - }() - - <-sign - runtime.GC() -} diff --git a/common/cache/lrucache.go b/common/cache/lrucache.go deleted file mode 100755 index 5a139bf..0000000 --- a/common/cache/lrucache.go +++ /dev/null @@ -1,148 +0,0 @@ -package cache - -// Modified by https://github.com/die-net/lrucache - -import ( - "container/list" - "sync" - "time" -) - -// Option is part of Functional Options Pattern -type Option func(*LruCache) - -// WithUpdateAgeOnGet update expires when Get element -func WithUpdateAgeOnGet() Option { - return func(l *LruCache) { - l.updateAgeOnGet = true - } -} - -// WithAge defined element max age (second) -func WithAge(maxAge int64) Option { - return func(l *LruCache) { - l.maxAge = maxAge - } -} - -// WithSize defined max length of LruCache -func WithSize(maxSize int) Option { - return func(l *LruCache) { - l.maxSize = maxSize - } -} - -// LruCache is a thread-safe, in-memory lru-cache that evicts the -// least recently used entries from memory when (if set) the entries are -// older than maxAge (in seconds). Use the New constructor to create one. -type LruCache struct { - maxAge int64 - maxSize int - mu sync.Mutex - cache map[interface{}]*list.Element - lru *list.List // Front is least-recent - updateAgeOnGet bool -} - -// NewLRUCache creates an LruCache -func NewLRUCache(options ...Option) *LruCache { - lc := &LruCache{ - lru: list.New(), - cache: make(map[interface{}]*list.Element), - } - - for _, option := range options { - option(lc) - } - - return lc -} - -// Get returns the interface{} representation of a cached response and a bool -// set to true if the key was found. -func (c *LruCache) Get(key interface{}) (interface{}, bool) { - c.mu.Lock() - defer c.mu.Unlock() - - le, ok := c.cache[key] - if !ok { - return nil, false - } - - if c.maxAge > 0 && le.Value.(*entry).expires <= time.Now().Unix() { - c.deleteElement(le) - c.maybeDeleteOldest() - - return nil, false - } - - c.lru.MoveToBack(le) - entry := le.Value.(*entry) - if c.maxAge > 0 && c.updateAgeOnGet { - entry.expires = time.Now().Unix() + c.maxAge - } - value := entry.value - - return value, true -} - -// Set stores the interface{} representation of a response for a given key. -func (c *LruCache) Set(key interface{}, value interface{}) { - c.mu.Lock() - defer c.mu.Unlock() - - expires := int64(0) - if c.maxAge > 0 { - expires = time.Now().Unix() + c.maxAge - } - - if le, ok := c.cache[key]; ok { - c.lru.MoveToBack(le) - e := le.Value.(*entry) - e.value = value - e.expires = expires - } else { - e := &entry{key: key, value: value, expires: expires} - c.cache[key] = c.lru.PushBack(e) - - if c.maxSize > 0 { - if len := c.lru.Len(); len > c.maxSize { - c.deleteElement(c.lru.Front()) - } - } - } - - c.maybeDeleteOldest() -} - -// Delete removes the value associated with a key. -func (c *LruCache) Delete(key string) { - c.mu.Lock() - - if le, ok := c.cache[key]; ok { - c.deleteElement(le) - } - - c.mu.Unlock() -} - -func (c *LruCache) maybeDeleteOldest() { - if c.maxAge > 0 { - now := time.Now().Unix() - for le := c.lru.Front(); le != nil && le.Value.(*entry).expires <= now; le = c.lru.Front() { - c.deleteElement(le) - } - } -} - -func (c *LruCache) deleteElement(le *list.Element) { - c.lru.Remove(le) - e := le.Value.(*entry) - delete(c.cache, e.key) -} - -type entry struct { - key interface{} - value interface{} - expires int64 -} diff --git a/common/cache/lrucache_test.go b/common/cache/lrucache_test.go deleted file mode 100755 index 31f9a91..0000000 --- a/common/cache/lrucache_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package cache - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var entries = []struct { - key string - value string -}{ - {"1", "one"}, - {"2", "two"}, - {"3", "three"}, - {"4", "four"}, - {"5", "five"}, -} - -func TestLRUCache(t *testing.T) { - c := NewLRUCache() - - for _, e := range entries { - c.Set(e.key, e.value) - } - - c.Delete("missing") - _, ok := c.Get("missing") - assert.False(t, ok) - - for _, e := range entries { - value, ok := c.Get(e.key) - if assert.True(t, ok) { - assert.Equal(t, e.value, value.(string)) - } - } - - for _, e := range entries { - c.Delete(e.key) - - _, ok := c.Get(e.key) - assert.False(t, ok) - } -} - -func TestLRUMaxAge(t *testing.T) { - c := NewLRUCache(WithAge(86400)) - - now := time.Now().Unix() - expected := now + 86400 - - // Add one expired entry - c.Set("foo", "bar") - c.lru.Back().Value.(*entry).expires = now - - // Reset - c.Set("foo", "bar") - e := c.lru.Back().Value.(*entry) - assert.True(t, e.expires >= now) - c.lru.Back().Value.(*entry).expires = now - - // Set a few and verify expiration times - for _, s := range entries { - c.Set(s.key, s.value) - e := c.lru.Back().Value.(*entry) - assert.True(t, e.expires >= expected && e.expires <= expected+10) - } - - // Make sure we can get them all - for _, s := range entries { - _, ok := c.Get(s.key) - assert.True(t, ok) - } - - // Expire all entries - for _, s := range entries { - le, ok := c.cache[s.key] - if assert.True(t, ok) { - le.Value.(*entry).expires = now - } - } - - // Get one expired entry, which should clear all expired entries - _, ok := c.Get("3") - assert.False(t, ok) - assert.Equal(t, c.lru.Len(), 0) -} - -func TestLRUpdateOnGet(t *testing.T) { - c := NewLRUCache(WithAge(86400), WithUpdateAgeOnGet()) - - now := time.Now().Unix() - expires := now + 86400/2 - - // Add one expired entry - c.Set("foo", "bar") - c.lru.Back().Value.(*entry).expires = expires - - _, ok := c.Get("foo") - assert.True(t, ok) - assert.True(t, c.lru.Back().Value.(*entry).expires > expires) -} - -func TestMaxSize(t *testing.T) { - c := NewLRUCache(WithSize(2)) - // Add one expired entry - c.Set("foo", "bar") - _, ok := c.Get("foo") - assert.True(t, ok) - - c.Set("bar", "foo") - c.Set("baz", "foo") - - _, ok = c.Get("foo") - assert.False(t, ok) -} diff --git a/common/domain-trie/node.go b/common/domain-trie/node.go deleted file mode 100755 index be8ba91..0000000 --- a/common/domain-trie/node.go +++ /dev/null @@ -1,26 +0,0 @@ -package trie - -// Node is the trie's node -type Node struct { - Data interface{} - children map[string]*Node -} - -func (n *Node) getChild(s string) *Node { - return n.children[s] -} - -func (n *Node) hasChild(s string) bool { - return n.getChild(s) != nil -} - -func (n *Node) addChild(s string, child *Node) { - n.children[s] = child -} - -func newNode(data interface{}) *Node { - return &Node{ - Data: data, - children: map[string]*Node{}, - } -} diff --git a/common/domain-trie/tire.go b/common/domain-trie/tire.go deleted file mode 100755 index f4e87ff..0000000 --- a/common/domain-trie/tire.go +++ /dev/null @@ -1,92 +0,0 @@ -package trie - -import ( - "errors" - "strings" -) - -const ( - wildcard = "*" - domainStep = "." -) - -var ( - // ErrInvalidDomain means insert domain is invalid - ErrInvalidDomain = errors.New("invalid domain") -) - -// Trie contains the main logic for adding and searching nodes for domain segments. -// support wildcard domain (e.g *.google.com) -type Trie struct { - root *Node -} - -func isValidDomain(domain string) bool { - return domain != "" && domain[0] != '.' && domain[len(domain)-1] != '.' -} - -// Insert adds a node to the trie. -// Support -// 1. www.example.com -// 2. *.example.com -// 3. subdomain.*.example.com -func (t *Trie) Insert(domain string, data interface{}) error { - if !isValidDomain(domain) { - return ErrInvalidDomain - } - - parts := strings.Split(domain, domainStep) - node := t.root - // reverse storage domain part to save space - for i := len(parts) - 1; i >= 0; i-- { - part := parts[i] - if !node.hasChild(part) { - node.addChild(part, newNode(nil)) - } - - node = node.getChild(part) - } - - node.Data = data - return nil -} - -// Search is the most important part of the Trie. -// Priority as: -// 1. static part -// 2. wildcard domain -func (t *Trie) Search(domain string) *Node { - if !isValidDomain(domain) { - return nil - } - parts := strings.Split(domain, domainStep) - - n := t.root - for i := len(parts) - 1; i >= 0; i-- { - part := parts[i] - - var child *Node - if !n.hasChild(part) { - if !n.hasChild(wildcard) { - return nil - } - - child = n.getChild(wildcard) - } else { - child = n.getChild(part) - } - - n = child - } - - if n.Data == nil { - return nil - } - - return n -} - -// New returns a new, empty Trie. -func New() *Trie { - return &Trie{root: newNode(nil)} -} diff --git a/common/domain-trie/trie_test.go b/common/domain-trie/trie_test.go deleted file mode 100755 index 228106c..0000000 --- a/common/domain-trie/trie_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package trie - -import ( - "net" - "testing" -) - -var localIP = net.IP{127, 0, 0, 1} - -func TestTrie_Basic(t *testing.T) { - tree := New() - domains := []string{ - "example.com", - "google.com", - } - - for _, domain := range domains { - tree.Insert(domain, localIP) - } - - node := tree.Search("example.com") - if node == nil { - t.Error("should not recv nil") - } - - if !node.Data.(net.IP).Equal(localIP) { - t.Error("should equal 127.0.0.1") - } - - if tree.Insert("", localIP) == nil { - t.Error("should return error") - } -} - -func TestTrie_Wildcard(t *testing.T) { - tree := New() - domains := []string{ - "*.example.com", - "sub.*.example.com", - "*.dev", - } - - for _, domain := range domains { - tree.Insert(domain, localIP) - } - - if tree.Search("sub.example.com") == nil { - t.Error("should not recv nil") - } - - if tree.Search("sub.foo.example.com") == nil { - t.Error("should not recv nil") - } - - if tree.Search("foo.sub.example.com") != nil { - t.Error("should recv nil") - } - - if tree.Search("foo.example.dev") != nil { - t.Error("should recv nil") - } - - if tree.Search("example.com") != nil { - t.Error("should recv nil") - } -} - -func TestTrie_Boundary(t *testing.T) { - tree := New() - tree.Insert("*.dev", localIP) - - if err := tree.Insert(".", localIP); err == nil { - t.Error("should recv err") - } - - if err := tree.Insert(".com", localIP); err == nil { - t.Error("should recv err") - } - - if tree.Search("dev") != nil { - t.Error("should recv nil") - } - - if tree.Search(".dev") != nil { - t.Error("should recv nil") - } -} diff --git a/common/fakeip/pool.go b/common/fakeip/pool.go deleted file mode 100755 index 1427e80..0000000 --- a/common/fakeip/pool.go +++ /dev/null @@ -1,107 +0,0 @@ -package fakeip - -import ( - "errors" - "net" - "sync" - - "github.com/xjasonlyu/tun2socks/common/cache" -) - -// Pool is a implementation about fake ip generator without storage -type Pool struct { - max uint32 - min uint32 - gateway uint32 - offset uint32 - mux *sync.Mutex - cache *cache.LruCache -} - -// Lookup return a fake ip with host -func (p *Pool) Lookup(host string) net.IP { - p.mux.Lock() - defer p.mux.Unlock() - if ip, exist := p.cache.Get(host); exist { - return ip.(net.IP) - } - - ip := p.get(host) - p.cache.Set(host, ip) - return ip -} - -// LookBack return host with the fake ip -func (p *Pool) LookBack(ip net.IP) (string, bool) { - p.mux.Lock() - defer p.mux.Unlock() - - if ip = ip.To4(); ip == nil { - return "", false - } - - n := ipToUint(ip.To4()) - offset := n - p.min + 1 - - if host, exist := p.cache.Get(offset); exist { - return host.(string), true - } - - return "", false -} - -// Gateway return gateway ip -func (p *Pool) Gateway() net.IP { - return uintToIP(p.gateway) -} - -func (p *Pool) get(host string) net.IP { - current := p.offset - for { - p.offset = (p.offset + 1) % (p.max - p.min) - // Avoid infinite loops - if p.offset == current { - break - } - - if _, exist := p.cache.Get(p.offset); !exist { - break - } - } - ip := uintToIP(p.min + p.offset - 1) - p.cache.Set(p.offset, host) - return ip -} - -func ipToUint(ip net.IP) uint32 { - v := uint32(ip[0]) << 24 - v += uint32(ip[1]) << 16 - v += uint32(ip[2]) << 8 - v += uint32(ip[3]) - return v -} - -func uintToIP(v uint32) net.IP { - return net.IPv4(byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) -} - -// New return Pool instance -func New(ipnet *net.IPNet, size int) (*Pool, error) { - min := ipToUint(ipnet.IP) + 2 - - ones, bits := ipnet.Mask.Size() - total := 1<> 4) -} - -func PeekProtocol(data []byte) string { - switch uint8(data[9]) { - case PROTOCOL_ICMP: - return "icmp" - case PROTOCOL_TCP: - return "tcp" - case PROTOCOL_UDP: - return "udp" - default: - return "unknown" - } -} - -func PeekSourceAddress(data []byte) net.IP { - return net.IP(data[12:16]) -} - -func PeekSourcePort(data []byte) uint16 { - ihl := uint8(data[0] & 0x0f) - return binary.BigEndian.Uint16(data[ihl*4 : ihl*4+2]) -} - -func PeekDestinationAddress(data []byte) net.IP { - return net.IP(data[16:20]) -} - -func PeekDestinationPort(data []byte) uint16 { - ihl := uint8(data[0] & 0x0f) - return binary.BigEndian.Uint16(data[ihl*4+2 : ihl*4+4]) -} - -func IsSYNSegment(data []byte) bool { - ihl := uint8(data[0] & 0x0f) - if uint8(data[ihl*4+13]&(1<<1)) == 0 { - return false - } else { - return true - } -} diff --git a/common/pool/pool.go b/common/pool/pool.go deleted file mode 100644 index 7c201e7..0000000 --- a/common/pool/pool.go +++ /dev/null @@ -1,14 +0,0 @@ -package pool - -import ( - "sync" -) - -const ( - // io.Copy default buffer size is 32 KiB - // define a buffer of 20 KiB to reduce the memory of each TCP relay - bufferSize = 20 * 1024 -) - -// BufPool provide buffer for relay -var BufPool = sync.Pool{New: func() interface{} { return make([]byte, bufferSize) }} diff --git a/component/fakedns/fakedns.go b/component/fakedns/fakedns.go deleted file mode 100644 index a0f484f..0000000 --- a/component/fakedns/fakedns.go +++ /dev/null @@ -1,16 +0,0 @@ -package fakedns - -import ( - "net" -) - -type FakeDNS interface { - Start() error - Stop() error - - // Resolve a fake dns response for the specify request. - Resolve([]byte) ([]byte, error) - - // IPToHost returns the corresponding domain for the given IP. - IPToHost(ip net.IP) (string, bool) -} diff --git a/component/fakedns/middleware.go b/component/fakedns/middleware.go deleted file mode 100644 index 0bd6ddd..0000000 --- a/component/fakedns/middleware.go +++ /dev/null @@ -1,130 +0,0 @@ -package fakedns - -import ( - "context" - "net" - "strings" - "time" - - D "github.com/miekg/dns" - - T "github.com/xjasonlyu/tun2socks/common/domain-trie" - F "github.com/xjasonlyu/tun2socks/common/fakeip" -) - -var backendDNS []string - -func RegisterDNS(dns string) { - backendDNS = append(backendDNS, strings.Split(dns, ",")...) -} - -func dnsExchange(r *D.Msg) (msg *D.Msg) { - defer func() { - if msg == nil { - // empty DNS response - rr := &D.A{} - rr.Hdr = D.RR_Header{Name: r.Question[0].Name, Rrtype: D.TypeA, Class: D.ClassINET, Ttl: dnsDefaultTTL} - msg = r.Copy() - msg.Answer = []D.RR{rr} - setMsgTTL(msg, dnsDefaultTTL) - } - }() - - c := new(D.Client) - c.Net = "tcp" - for _, dns := range backendDNS { - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - msg, _, _ = c.ExchangeContext(ctx, r, dns) - cancel() // call cancel as soon as the operations running in this Context complete - if msg != nil { - // success, exit query - goto Out - } - } -Out: - return msg -} - -func resolve(hosts *T.Trie, pool *F.Pool, r *D.Msg) (msg *D.Msg) { - defer func() { - if msg != nil { - msg.SetReply(r) - } - }() - - if msg = hostResolve(hosts, r); msg != nil { - return msg - } - - q := r.Question[0] - if q.Qtype != D.TypeA || q.Qclass != D.ClassINET { - return dnsExchange(r) - } - - return fakeResolve(pool, r) -} - -func fakeResolve(pool *F.Pool, r *D.Msg) *D.Msg { - q := r.Question[0] - host := strings.TrimRight(q.Name, ".") - - rr := &D.A{} - rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeA, Class: D.ClassINET, Ttl: dnsFakeTTL} - ip := pool.Lookup(host) - rr.A = ip - - msg := r.Copy() - msg.Answer = []D.RR{rr} - setMsgTTL(msg, dnsFakeTTL) - return msg -} - -func hostResolve(hosts *T.Trie, r *D.Msg) *D.Msg { - if hosts == nil { - return nil - } - - q := r.Question[0] - if q.Qtype != D.TypeA && q.Qtype != D.TypeAAAA { - return nil - } - - domain := strings.TrimRight(q.Name, ".") - host := hosts.Search(domain) - if host == nil { - return nil - } - - ip := host.Data.(net.IP) - if q.Qtype == D.TypeAAAA && ip.To16() == nil { - return nil - } else if q.Qtype == D.TypeA && ip.To4() == nil { - return nil - } - - var rr D.RR - if q.Qtype == D.TypeAAAA { - record := &D.AAAA{} - record.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeAAAA, Class: D.ClassINET, Ttl: dnsDefaultTTL} - record.AAAA = ip - rr = record - } else { - record := &D.A{} - record.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeA, Class: D.ClassINET, Ttl: dnsDefaultTTL} - record.A = ip - rr = record - } - - msg := r.Copy() - msg.Answer = []D.RR{rr} - setMsgTTL(msg, dnsDefaultTTL) - return msg -} - -func newHandler(hosts *T.Trie, pool *F.Pool) handler { - return func(w D.ResponseWriter, r *D.Msg) { - msg := resolve(hosts, pool, r) - w.WriteMsg(msg) - return - } -} diff --git a/component/fakedns/resolver.go b/component/fakedns/resolver.go deleted file mode 100644 index 91861da..0000000 --- a/component/fakedns/resolver.go +++ /dev/null @@ -1,133 +0,0 @@ -package fakedns - -import ( - "errors" - "fmt" - "net" - "strings" - - D "github.com/miekg/dns" - - T "github.com/xjasonlyu/tun2socks/common/domain-trie" - F "github.com/xjasonlyu/tun2socks/common/fakeip" -) - -const ( - // TTL - dnsFakeTTL uint32 = 1 - dnsDefaultTTL uint32 = 600 - - // Resolver default value - dnsCacheSize = 1000 - dnsFakeIPRange = "198.18.0.0/15" -) - -type handler = D.HandlerFunc - -type Resolver struct { - h handler - p *F.Pool - t *T.Trie - - *D.Server - ServeAddr string -} - -func (r *Resolver) ServeDNS(w D.ResponseWriter, req *D.Msg) { - if len(req.Question) == 0 { - D.HandleFailed(w, req) - return - } - r.h(w, req) -} - -func (r *Resolver) Start() error { - _, port, err := net.SplitHostPort(r.ServeAddr) - if port == "0" || port == "" || err != nil { - return errors.New("address format error") - } - - udpAddr, err := net.ResolveUDPAddr("udp", r.ServeAddr) - if err != nil { - return err - } - - pc, err := net.ListenUDP("udp", udpAddr) - if err != nil { - return err - } - - r.Server = &D.Server{Addr: r.ServeAddr, PacketConn: pc, Handler: r.h} - go func() { - r.ActivateAndServe() - }() - - return nil -} - -func (r *Resolver) Stop() error { - return r.Shutdown() -} - -func (r *Resolver) IPToHost(ip net.IP) (string, bool) { - return r.p.LookBack(ip) -} - -func (r *Resolver) Resolve(request []byte) ([]byte, error) { - if err := D.IsMsg(request); err != nil { - return nil, err - } - - req := new(D.Msg) - if err := req.Unpack(request); err != nil { - return nil, errors.New("cannot handle dns query: failed to unpack") - } - - if len(req.Question) == 0 { - return nil, errors.New("cannot handle dns query: invalid question length") - } - - msg := resolve(r.t, r.p, req) - if msg == nil { - return nil, errors.New("cannot resolve dns query: msg is nil") - } - resp, err := msg.Pack() - if err != nil { - return nil, fmt.Errorf("failed to pack dns answer: %v", err) - } - return resp, nil -} - -func NewResolver(a, h string) (*Resolver, error) { - _, ipnet, _ := net.ParseCIDR(dnsFakeIPRange) - - pool, err := F.New(ipnet, dnsCacheSize) - if err != nil { - return nil, err - } - - tree := func(str string) *T.Trie { - tree := T.New() - s := strings.Split(str, ",") - for _, host := range s { - m := strings.Split(host, "=") - if len(m) != 2 { - continue - } - domain := strings.TrimSpace(m[0]) - target := strings.TrimSpace(m[1]) - if err := tree.Insert(domain, net.ParseIP(target)); err != nil { - panic(fmt.Sprintf("add hosts error: %v", err)) - } - } - return tree - }(h) - - handler := newHandler(tree, pool) - return &Resolver{ - h: handler, - p: pool, - t: tree, - ServeAddr: a, - }, nil -} diff --git a/component/fakedns/utils.go b/component/fakedns/utils.go deleted file mode 100644 index dfbc9aa..0000000 --- a/component/fakedns/utils.go +++ /dev/null @@ -1,19 +0,0 @@ -package fakedns - -import ( - D "github.com/miekg/dns" -) - -func setMsgTTL(msg *D.Msg, ttl uint32) { - for _, answer := range msg.Answer { - answer.Header().Ttl = ttl - } - - for _, ns := range msg.Ns { - ns.Header().Ttl = ttl - } - - for _, extra := range msg.Extra { - extra.Header().Ttl = ttl - } -} diff --git a/component/session/css/bootstrap.min.css b/component/session/css/bootstrap.min.css deleted file mode 100644 index 21d10ba..0000000 --- a/component/session/css/bootstrap.min.css +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v4.5.2 (https://getbootstrap.com/) - * Copyright 2011-2020 The Bootstrap Authors - * Copyright 2011-2020 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([class]){color:inherit;text-decoration:none}a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014\00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code{font-size:87.5%;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-sm-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-sm-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-sm-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-sm-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-sm-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-sm-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-md-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-md-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-md-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-md-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-md-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-md-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-lg-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-lg-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-lg-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-lg-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-lg-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-lg-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-xl-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-xl-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-xl-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-xl-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-xl-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-xl-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;margin-bottom:1rem;color:#212529}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{color:#212529;background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#7abaff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-secondary tbody+tbody,.table-secondary td,.table-secondary th,.table-secondary thead th{border-color:#b3b7bb}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-success tbody+tbody,.table-success td,.table-success th,.table-success thead th{border-color:#8fd19e}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-info tbody+tbody,.table-info td,.table-info th,.table-info thead th{border-color:#86cfda}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-warning tbody+tbody,.table-warning td,.table-warning th,.table-warning thead th{border-color:#ffdf7e}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-danger tbody+tbody,.table-danger td,.table-danger th,.table-danger thead th{border-color:#ed969e}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-light tbody+tbody,.table-light td,.table-light th,.table-light thead th{border-color:#fbfcfc}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#95999c}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#343a40;border-color:#454d55}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#343a40}.table-dark td,.table-dark th,.table-dark thead th{border-color:#454d55}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{color:#fff;background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{-webkit-appearance:none;-moz-appearance:none;appearance:none}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;font-size:1rem;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control[multiple],select.form-control[size]{height:auto}textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;left:0;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(40,167,69,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#28a745;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-valid,.was-validated .custom-select:valid{border-color:#28a745;padding-right:calc(.75em + 2.3125rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-valid:focus,.was-validated .custom-select:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{border-color:#28a745}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{border-color:#34ce57;background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;left:0;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-invalid,.was-validated .custom-select:invalid{border-color:#dc3545;padding-right:calc(.75em + 2.3125rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-invalid:focus,.was-validated .custom-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{border-color:#dc3545}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{border-color:#e4606d;background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;-ms-flex-negative:0;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#212529;text-align:center;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529;text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#0069d9;border-color:#0062cc;box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{color:#fff;background-color:#5a6268;border-color:#545b62;box-shadow:0 0 0 .2rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(130,138,145,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#218838;border-color:#1e7e34;box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#138496;border-color:#117a8b;box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{color:#212529;background-color:#e0a800;border-color:#d39e00;box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c82333;border-color:#bd2130;box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{color:#212529;background-color:#e2e6ea;border-color:#dae0e5;box-shadow:0 0 0 .2rem rgba(216,217,219,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(216,217,219,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{color:#fff;background-color:#23272b;border-color:#1d2124;box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-outline-primary{color:#007bff;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;text-decoration:none}.btn-link:hover{color:#0056b3;text-decoration:underline}.btn-link.focus,.btn-link:focus{text-decoration:underline}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-left{right:auto;left:0}.dropdown-menu-right{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-left{right:auto;left:0}.dropdown-menu-sm-right{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-left{right:auto;left:0}.dropdown-menu-md-right{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-left{right:auto;left:0}.dropdown-menu-lg-right{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-left{right:auto;left:0}.dropdown-menu-xl-right{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:1 1 auto;flex:1 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;min-width:0;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.input-group>.form-control-plaintext+.custom-file,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn:focus,.input-group-prepend .btn:focus{z-index:3}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group-lg>.custom-select,.input-group-lg>.form-control:not(textarea){height:calc(1.5em + 1rem + 2px)}.input-group-lg>.custom-select,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.custom-select,.input-group-sm>.form-control:not(textarea){height:calc(1.5em + .5rem + 2px)}.input-group-sm>.custom-select,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;z-index:1;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;left:0;z-index:-1;width:1rem;height:1.25rem;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;border-color:#007bff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label::before{border-color:#80bdff}.custom-control-input:not(:disabled):active~.custom-control-label::before{color:#fff;background-color:#b3d7ff;border-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label,.custom-control-input[disabled]~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before,.custom-control-input[disabled]~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0;vertical-align:top}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";background-color:#fff;border:#adb5bd solid 1px}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background:no-repeat 50%/50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{border-color:#007bff;background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label::before{left:-2.25rem;width:1.75rem;pointer-events:all;border-radius:.5rem}.custom-switch .custom-control-label::after{top:calc(.25rem + 2px);left:calc(-2.25rem + 2px);width:calc(1rem - 4px);height:calc(1rem - 4px);background-color:#adb5bd;border-radius:.5rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-switch .custom-control-label::after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label::after{background-color:#fff;-webkit-transform:translateX(.75rem);transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem 1.75rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{display:none}.custom-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}.custom-select-sm{height:calc(1.5em + .5rem + 2px);padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.custom-select-lg{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.custom-file{position:relative;display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(1.5em + .75rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:disabled~.custom-file-label,.custom-file-input[disabled]~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-input~.custom-file-label[data-browse]::after{content:attr(data-browse)}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(1.5em + .75rem);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:1.4rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{-moz-transition:none;transition:none}}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#007bff;border:0;border-radius:1rem;-ms-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{-ms-transition:none;transition:none}}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#adb5bd}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#adb5bd}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item,.nav-fill>.nav-link{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar .container,.navbar .container-fluid,.navbar .container-lg,.navbar .container-md,.navbar .container-sm,.navbar .container-xl{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.5%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.5%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;min-height:1px;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom,.card-img-top{-ms-flex-negative:0;flex-shrink:0;width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{-ms-flex:1 0 0%;flex:1 0 0%;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion{overflow-anchor:none}.accordion>.card{overflow:hidden}.accordion>.card:not(:last-of-type){border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:not(:first-of-type){border-top-left-radius:0;border-top-right-radius:0}.accordion>.card>.card-header{border-radius:0;margin-bottom:-1px}.breadcrumb{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item{display:-ms-flexbox;display:flex}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:3;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.badge{transition:none}}a.badge:focus,a.badge:hover{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}a.badge-primary:focus,a.badge-primary:hover{color:#fff;background-color:#0062cc}a.badge-primary.focus,a.badge-primary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.badge-secondary{color:#fff;background-color:#6c757d}a.badge-secondary:focus,a.badge-secondary:hover{color:#fff;background-color:#545b62}a.badge-secondary.focus,a.badge-secondary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.badge-success{color:#fff;background-color:#28a745}a.badge-success:focus,a.badge-success:hover{color:#fff;background-color:#1e7e34}a.badge-success.focus,a.badge-success:focus{outline:0;box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.badge-info{color:#fff;background-color:#17a2b8}a.badge-info:focus,a.badge-info:hover{color:#fff;background-color:#117a8b}a.badge-info.focus,a.badge-info:focus{outline:0;box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.badge-warning{color:#212529;background-color:#ffc107}a.badge-warning:focus,a.badge-warning:hover{color:#212529;background-color:#d39e00}a.badge-warning.focus,a.badge-warning:focus{outline:0;box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.badge-danger{color:#fff;background-color:#dc3545}a.badge-danger:focus,a.badge-danger:hover{color:#fff;background-color:#bd2130}a.badge-danger.focus,a.badge-danger:focus{outline:0;box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.badge-light{color:#212529;background-color:#f8f9fa}a.badge-light:focus,a.badge-light:hover{color:#212529;background-color:#dae0e5}a.badge-light.focus,a.badge-light:focus{outline:0;box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.badge-dark{color:#fff;background-color:#343a40}a.badge-dark:focus,a.badge-dark:hover{color:#fff;background-color:#1d2124}a.badge-dark.focus,a.badge-dark:focus{outline:0;box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;line-height:0;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:hover{color:#000;text-decoration:none}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{opacity:.75}button.close{padding:0;background-color:transparent;border:0}a.close.disabled{pointer-events:none}.toast{-ms-flex-preferred-size:350px;flex-basis:350px;max-width:350px;font-size:.875rem;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem rgba(0,0,0,.1);opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.25rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-50px);transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:none;transform:none}.modal.modal-static .modal-dialog{-webkit-transform:scale(1.02);transform:scale(1.02)}.modal-dialog-scrollable{display:-ms-flexbox;display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-footer,.modal-dialog-scrollable .modal-header{-ms-flex-negative:0;flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered::before{display:block;height:calc(100vh - 1rem);height:-webkit-min-content;height:-moz-min-content;height:min-content;content:""}.modal-dialog-centered.modal-dialog-scrollable{-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;height:100%}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable::before{content:none}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .close{padding:1rem 1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered::before{height:calc(100vh - 3.5rem);height:-webkit-min-content;height:-moz-min-content;height:min-content}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top]>.arrow,.bs-popover-top>.arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=top]>.arrow::before,.bs-popover-top>.arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top]>.arrow::after,.bs-popover-top>.arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right]>.arrow,.bs-popover-right>.arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right]>.arrow::before,.bs-popover-right>.arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right]>.arrow::after,.bs-popover-right>.arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom]>.arrow,.bs-popover-bottom>.arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=bottom]>.arrow::before,.bs-popover-bottom>.arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom]>.arrow::after,.bs-popover-bottom>.arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left]>.arrow,.bs-popover-left>.arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left]>.arrow::before,.bs-popover-left>.arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left]>.arrow::after,.bs-popover-left>.arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{-ms-touch-action:pan-y;touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-right,.carousel-item-next:not(.carousel-item-left){-webkit-transform:translateX(100%);transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){-webkit-transform:translateX(-100%);transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;-webkit-transform:none;transform:none}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:no-repeat 50%/100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}@-webkit-keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:spinner-border .75s linear infinite;animation:spinner-border .75s linear infinite}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1;-webkit-transform:none;transform:none}}@keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1;-webkit-transform:none;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:spinner-grow .75s linear infinite;animation:spinner-grow .75s linear infinite}.spinner-grow-sm{width:1rem;height:1rem}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;-ms-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;-ms-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;-ms-user-select:none!important;user-select:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:auto;content:"";background-color:rgba(0,0,0,0)}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0056b3!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#494f54!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#19692c!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#0f6674!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#ba8b00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#a71d2a!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#cbd3da!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#121416!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-decoration-none{text-decoration:none!important}.text-break{word-break:break-word!important;overflow-wrap:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}} -/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/component/session/server.go b/component/session/server.go deleted file mode 100644 index 6d4a1b5..0000000 --- a/component/session/server.go +++ /dev/null @@ -1,221 +0,0 @@ -package session - -import ( - "bufio" - "encoding/json" - "errors" - "fmt" - "io" - "net" - "net/http" - "runtime" - "sort" - "sync" - "sync/atomic" - "time" - - C "github.com/xjasonlyu/tun2socks/constant" - - "github.com/gobuffalo/packr/v2" -) - -const maxClosedSessions = 100 - -type Server struct { - sync.Mutex - *http.Server - - ServeAddr string - - trafficUp int64 - trafficDown int64 - - activeSessionMap sync.Map - closedSessionList []Session -} - -func New(addr string) *Server { - return &Server{ - ServeAddr: addr, - } -} - -func (s *Server) getSessions() (activeSessions, closedSessions []Session) { - // Slice of active sessions - s.activeSessionMap.Range(func(key, value interface{}) bool { - session := value.(*Session) - activeSessions = append(activeSessions, *session) - return true - }) - - // Slice of closed sessions - s.Lock() - defer s.Unlock() - closedSessions = append([]Session(nil), s.closedSessionList...) - return -} - -func (s *Server) serveJSON(w http.ResponseWriter, _ *http.Request) { - activeSessions, closedSessions := s.getSessions() - - // calculate traffic - trafficUp := atomic.LoadInt64(&s.trafficUp) - trafficDown := atomic.LoadInt64(&s.trafficDown) - for _, session := range activeSessions { - trafficUp += session.UploadBytes - trafficDown += session.DownloadBytes - } - - status := &Status{ - platform(), - C.Version, - cpu(), - mem(), - uptime(), - trafficUp + trafficDown, - trafficUp, - trafficDown, - runtime.NumGoroutine(), - activeSessions, - closedSessions, - } - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(status) -} - -func (s *Server) serveHTML(resp http.ResponseWriter, _ *http.Request) { - activeSessions, closedSessions := s.getSessions() - - tablePrint := func(w io.Writer, sessions []Session) { - // Sort by session start time. - sort.Slice(sessions, func(i, j int) bool { - return sessions[i].SessionStart.After(sessions[j].SessionStart) - }) - _, _ = fmt.Fprintf(w, "
\n") - _, _ = fmt.Fprintf(w, "\n") - - for _, session := range sessions { - _, _ = fmt.Fprintf(w, "\n", - session.Process, - session.Network, - date(session.SessionStart), - duration(session.SessionStart, session.SessionClose), - // session.DialerAddr, - session.ClientAddr, - session.TargetAddr, - byteCountSI(session.UploadBytes), - byteCountSI(session.DownloadBytes), - ) - } - _, _ = fmt.Fprintf(w, "
ProcessNetworkDateDurationClient AddrTarget AddrUploadDownload
%v%v%v%v%v%v%v%v
\n") - } - - w := bufio.NewWriter(resp) - // Html head - _, _ = fmt.Fprintf(w, ` - - - - - - Go-tun2socks - - - -
-

Go-tun2socks %s

`, C.Version) - // calculate traffic - trafficUp := atomic.LoadInt64(&s.trafficUp) - trafficDown := atomic.LoadInt64(&s.trafficDown) - for _, session := range activeSessions { - trafficUp += session.UploadBytes - trafficDown += session.DownloadBytes - } - // statistics - _, _ = fmt.Fprintf(w, `

Statistics (%d)

-
- - - - - -
Last Refresh TimePlatform VersionCPUMEMUptimeTotalUploadDownload
%v%v%v%v%v%v%v%v
-
`, - runtime.NumGoroutine(), - date(time.Now()), - platform(), - cpu(), - mem(), - uptime(), - byteCountSI(trafficUp+trafficDown), - byteCountSI(trafficUp), - byteCountSI(trafficDown), - ) - // Session table - _, _ = fmt.Fprintf(w, "

Active sessions (%d)

\n", len(activeSessions)) - tablePrint(w, activeSessions) - _, _ = fmt.Fprintf(w, "

Closed sessions (%d)

\n", len(closedSessions)) - tablePrint(w, closedSessions) - _, _ = fmt.Fprintf(w, "
\n") - _ = w.Flush() -} - -func (s *Server) Start() error { - _, port, err := net.SplitHostPort(s.ServeAddr) - if port == "0" || port == "" || err != nil { - return errors.New("address format error") - } - - tcpAddr, err := net.ResolveTCPAddr("tcp", s.ServeAddr) - if err != nil { - return err - } - - c, err := net.ListenTCP("tcp", tcpAddr) - if err != nil { - return err - } - - mux := http.NewServeMux() - mux.HandleFunc("/", s.serveHTML) - mux.HandleFunc("/json", s.serveJSON) - - box := packr.New("CSSBox", "./css") - mux.Handle("/css/", http.StripPrefix("/css/", http.FileServer(box))) - - s.Server = &http.Server{Addr: s.ServeAddr, Handler: mux} - go func() { - s.Serve(c) - }() - - return nil -} - -func (s *Server) Stop() error { - return s.Close() -} - -func (s *Server) AddSession(key interface{}, session *Session) { - if session != nil { - s.activeSessionMap.Store(key, session) - } -} - -func (s *Server) RemoveSession(key interface{}) { - if item, ok := s.activeSessionMap.Load(key); ok { - session := item.(*Session) - // delete first - s.activeSessionMap.Delete(key) - // record up & down traffic - atomic.AddInt64(&s.trafficUp, atomic.LoadInt64(&session.UploadBytes)) - atomic.AddInt64(&s.trafficDown, atomic.LoadInt64(&session.DownloadBytes)) - // move to closed sessions - s.Lock() - s.closedSessionList = append(s.closedSessionList, *session) - if len(s.closedSessionList) > maxClosedSessions { - s.closedSessionList = s.closedSessionList[1:] - } - s.Unlock() - } -} diff --git a/component/session/session.go b/component/session/session.go deleted file mode 100644 index 8ce0aef..0000000 --- a/component/session/session.go +++ /dev/null @@ -1,103 +0,0 @@ -package session - -import ( - "net" - "sync" - "sync/atomic" - "time" -) - -type Monitor interface { - Start() error - Stop() error - - // METHODS - AddSession(key interface{}, session *Session) - RemoveSession(key interface{}) -} - -type Status struct { - Platform string `json:"platform"` - Version string `json:"version"` - CPU string `json:"cpu"` - MEM string `json:"mem"` - Uptime string `json:"uptime"` - Total int64 `json:"total"` - Upload int64 `json:"upload"` - Download int64 `json:"download"` - Goroutines int `json:"goroutines"` - ActiveSessions []Session `json:"activeSessions"` - ClosedSessions []Session `json:"closedSessions"` -} - -type Session struct { - Process string `json:"process"` - Network string `json:"network"` - DialerAddr string `json:"dialerAddr"` - ClientAddr string `json:"clientAddr"` - TargetAddr string `json:"targetAddr"` - UploadBytes int64 `json:"upload"` - DownloadBytes int64 `json:"download"` - SessionStart time.Time `json:"sessionStart"` - SessionClose time.Time `json:"sessionClose"` -} - -// Track SessionConn -type Conn struct { - *Session - net.Conn - once sync.Once -} - -func (c *Conn) Read(b []byte) (n int, err error) { - n, err = c.Conn.Read(b) - if n > 0 { - atomic.AddInt64(&c.DownloadBytes, int64(n)) - } - return -} - -func (c *Conn) Write(b []byte) (n int, err error) { - n, err = c.Conn.Write(b) - if n > 0 { - atomic.AddInt64(&c.UploadBytes, int64(n)) - } - return -} - -func (c *Conn) Close() error { - c.once.Do(func() { - c.SessionClose = time.Now() - }) - return c.Conn.Close() -} - -// Track SessionPacketConn -type PacketConn struct { - *Session - net.PacketConn - once sync.Once -} - -func (c *PacketConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { - n, addr, err = c.PacketConn.ReadFrom(b) - if n > 0 { - atomic.AddInt64(&c.DownloadBytes, int64(n)) - } - return -} - -func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { - n, err = c.PacketConn.WriteTo(b, addr) - if n > 0 { - atomic.AddInt64(&c.UploadBytes, int64(n)) - } - return -} - -func (c *PacketConn) Close() error { - c.once.Do(func() { - c.SessionClose = time.Now() - }) - return c.PacketConn.Close() -} diff --git a/component/session/utils.go b/component/session/utils.go deleted file mode 100644 index 623aa0c..0000000 --- a/component/session/utils.go +++ /dev/null @@ -1,174 +0,0 @@ -package session - -import ( - "fmt" - "strings" - "time" - - C "github.com/shirou/gopsutil/cpu" - H "github.com/shirou/gopsutil/host" - M "github.com/shirou/gopsutil/mem" -) - -var startTime time.Time - -func init() { - startTime = time.Now() -} - -func cpu() string { - c, err := C.Percent(0, false) - if err != nil || len(c) != 1 { - return "N/A" - } - return fmt.Sprintf("%.1f%%", c[0]) -} - -func platform() string { - h, err := H.Info() - if err != nil { - return "N/A" - } - return fmt.Sprintf("%s-%s", h.Platform, h.KernelVersion) -} - -func mem() string { - m, err := M.VirtualMemory() - if err != nil { - return "N/A" - } - return fmt.Sprintf("%.1f%%", m.UsedPercent) -} - -func date(t time.Time) string { - return t.Format("Mon Jan 2 15:04:05") -} - -func duration(start, end time.Time) string { - var t time.Duration - if end.IsZero() { - t = time.Now().Sub(start) - } else { - t = end.Sub(start) - } - - switch { - case t < 1000*time.Millisecond: - t = t.Round(time.Millisecond) - default: - t = t.Round(time.Second) - } - return t.String() -} - -func uptime() string { - // Time difference function - diff := func(a, b time.Time) (year, month, day, hour, min, sec int) { - if a.Location() != b.Location() { - b = b.In(a.Location()) - } - if a.After(b) { - a, b = b, a - } - y1, M1, d1 := a.Date() - y2, M2, d2 := b.Date() - - h1, m1, s1 := a.Clock() - h2, m2, s2 := b.Clock() - - year = int(y2 - y1) - month = int(M2 - M1) - day = int(d2 - d1) - hour = int(h2 - h1) - min = int(m2 - m1) - sec = int(s2 - s1) - - // Normalize negative values - if sec < 0 { - sec += 60 - min-- - } - if min < 0 { - min += 60 - hour-- - } - if hour < 0 { - hour += 24 - day-- - } - if day < 0 { - // days in month: - t := time.Date(y1, M1, 32, 0, 0, 0, 0, time.UTC) - day += 32 - t.Day() - month-- - } - if month < 0 { - month += 12 - year-- - } - - return - } - - // Y M d h m s - now := time.Now() - year, month, day, hour, min, sec := diff(startTime, now) - - var Y, M, d, h, m, s string - - // Y M d - if year != 0 { - Y = fmt.Sprintf("%dY,", year) - } - - if month != 0 { - M = fmt.Sprintf("%dM,", month) - } - - if day != 0 { - d = fmt.Sprintf("%dd,", day) - } - - // h m s - if hour != 0 { - h = fmt.Sprintf("%dh", hour) - } - - if min != 0 { - m = fmt.Sprintf("%dm", min) - } - - if sec != 0 { - s = fmt.Sprintf("%ds", sec) - } - - return strings.Join([]string{Y, M, d, h, m, s}, "") -} - -func byteCountSI(b int64) string { - const unit = 1000 - if b < unit { - return fmt.Sprintf("%d B", b) - } - div, exp := int64(unit), 0 - for n := b / unit; n >= unit; n /= unit { - div *= unit - exp++ - } - return fmt.Sprintf("%.1f %cB", - float64(b)/float64(div), "kMGTPE"[exp]) -} - -func byteCountIEC(b int64) string { - const unit = 1024 - if b < unit { - return fmt.Sprintf("%d B", b) - } - div, exp := int64(unit), 0 - for n := b / unit; n >= unit; n /= unit { - div *= unit - exp++ - } - return fmt.Sprintf("%.1f %ciB", - float64(b)/float64(div), "KMGTPE"[exp]) -} diff --git a/constant/version.go b/constant/version.go deleted file mode 100644 index 32a3a4f..0000000 --- a/constant/version.go +++ /dev/null @@ -1,5 +0,0 @@ -package constant - -var ( - Version = "v0.0.0-0-00000000" -) diff --git a/core/addr.go b/core/addr.go deleted file mode 100755 index 436c04d..0000000 --- a/core/addr.go +++ /dev/null @@ -1,46 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/tcp.h" -#include -*/ -import "C" -import ( - "errors" - "net" - "strconv" - "unsafe" -) - -// ipaddr_ntoa() is using a global static buffer to return result, -// reentrants are not allowed, caller is required to lock lwipMutex. -func ipAddrNTOA(ipaddr C.struct_ip_addr) string { - return C.GoString(C.ipaddr_ntoa(&ipaddr)) -} - -func ipAddrATON(cp string, addr *C.struct_ip_addr) error { - ccp := C.CString(cp) - defer C.free(unsafe.Pointer(ccp)) - if r := C.ipaddr_aton(ccp, addr); r == 0 { - return errors.New("failed to convert IP address") - } else { - return nil - } -} - -func ParseTCPAddr(addr string, port uint16) *net.TCPAddr { - netAddr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(addr, strconv.Itoa(int(port)))) - if err != nil { - return nil - } - return netAddr -} - -func ParseUDPAddr(addr string, port uint16) *net.UDPAddr { - netAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(addr, strconv.Itoa(int(port)))) - if err != nil { - return nil - } - return netAddr -} diff --git a/core/buffer_pool.go b/core/buffer_pool.go deleted file mode 100755 index e60371a..0000000 --- a/core/buffer_pool.go +++ /dev/null @@ -1,35 +0,0 @@ -package core - -import ( - "sync" -) - -var pool *sync.Pool - -const BufSize = 2 * 1024 - -func SetBufferPool(p *sync.Pool) { - pool = p -} - -func NewBytes(size int) []byte { - if size <= BufSize { - return pool.Get().([]byte) - } else { - return make([]byte, size) - } -} - -func FreeBytes(b []byte) { - if len(b) >= BufSize { - pool.Put(b) - } -} - -func init() { - SetBufferPool(&sync.Pool{ - New: func() interface{} { - return make([]byte, BufSize) - }, - }) -} diff --git a/core/c/core/altcp.c b/core/c/core/altcp.c deleted file mode 100755 index d42b727..0000000 --- a/core/c/core/altcp.c +++ /dev/null @@ -1,681 +0,0 @@ -/** - * @file - * @defgroup altcp Application layered TCP Functions - * @ingroup altcp_api - * - * This file contains the common functions for altcp to work. - * For more details see @ref altcp_api. - */ - -/** - * @defgroup altcp_api Application layered TCP Introduction - * @ingroup callbackstyle_api - * - * Overview - * -------- - * altcp (application layered TCP connection API; to be used from TCPIP thread) - * is an abstraction layer that prevents applications linking hard against the - * @ref tcp.h functions while providing the same functionality. It is used to - * e.g. add SSL/TLS (see LWIP_ALTCP_TLS) or proxy-connect support to an application - * written for the tcp callback API without that application knowing the - * protocol details. - * - * * This interface mimics the tcp callback API to the application while preventing - * direct linking (much like virtual functions). - * * This way, an application can make use of other application layer protocols - * on top of TCP without knowing the details (e.g. TLS, proxy connection). - * * This is achieved by simply including "lwip/altcp.h" instead of "lwip/tcp.h", - * replacing "struct tcp_pcb" with "struct altcp_pcb" and prefixing all functions - * with "altcp_" instead of "tcp_". - * - * With altcp support disabled (LWIP_ALTCP==0), applications written against the - * altcp API can still be compiled but are directly linked against the tcp.h - * callback API and then cannot use layered protocols. To minimize code changes - * in this case, the use of altcp_allocators is strongly suggested. - * - * Usage - * ----- - * To make use of this API from an existing tcp raw API application: - * * Include "lwip/altcp.h" instead of "lwip/tcp.h" - * * Replace "struct tcp_pcb" with "struct altcp_pcb" - * * Prefix all called tcp API functions with "altcp_" instead of "tcp_" to link - * against the altcp functions - * * @ref altcp_new (and @ref altcp_new_ip_type/@ref altcp_new_ip6) take - * an @ref altcp_allocator_t as an argument, whereas the original tcp API - * functions take no arguments. - * * An @ref altcp_allocator_t allocator is an object that holds a pointer to an - * allocator object and a corresponding state (e.g. for TLS, the corresponding - * state may hold certificates or keys). This way, the application does not - * even need to know if it uses TLS or pure TCP, this is handled at runtime - * by passing a specific allocator. - * * An application can alternatively bind hard to the altcp_tls API by calling - * @ref altcp_tls_new or @ref altcp_tls_wrap. - * * The TLS layer is not directly implemented by lwIP, but a port to mbedTLS is - * provided. - * * Another altcp layer is proxy-connect to use TLS behind a HTTP proxy (see - * @ref altcp_proxyconnect.h) - * - * altcp_allocator_t - * ----------------- - * An altcp allocator is created by the application by combining an allocator - * callback function and a corresponding state, e.g.:\code{.c} - * static const unsigned char cert[] = {0x2D, ... (see mbedTLS doc for how to create this)}; - * struct altcp_tls_config * conf = altcp_tls_create_config_client(cert, sizeof(cert)); - * altcp_allocator_t tls_allocator = { - * altcp_tls_alloc, conf - * }; - * \endcode - * - * - * struct altcp_tls_config - * ----------------------- - * The struct altcp_tls_config holds state that is needed to create new TLS client - * or server connections (e.g. certificates and private keys). - * - * It is not defined by lwIP itself but by the TLS port (e.g. altcp_tls to mbedTLS - * adaption). However, the parameters used to create it are defined in @ref - * altcp_tls.h (see @ref altcp_tls_create_config_server_privkey_cert for servers - * and @ref altcp_tls_create_config_client/@ref altcp_tls_create_config_client_2wayauth - * for clients). - * - * For mbedTLS, ensure that certificates can be parsed by 'mbedtls_x509_crt_parse()' and - * private keys can be parsed by 'mbedtls_pk_parse_key()'. - */ - -/* - * Copyright (c) 2017 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ - -#include "lwip/opt.h" - -#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/altcp.h" -#include "lwip/priv/altcp_priv.h" -#include "lwip/altcp_tcp.h" -#include "lwip/tcp.h" -#include "lwip/mem.h" - -#include - -extern const struct altcp_functions altcp_tcp_functions; - -/** - * For altcp layer implementations only: allocate a new struct altcp_pcb from the pool - * and zero the memory - */ -struct altcp_pcb * -altcp_alloc(void) -{ - struct altcp_pcb *ret = (struct altcp_pcb *)memp_malloc(MEMP_ALTCP_PCB); - if (ret != NULL) { - memset(ret, 0, sizeof(struct altcp_pcb)); - } - return ret; -} - -/** - * For altcp layer implementations only: return a struct altcp_pcb to the pool - */ -void -altcp_free(struct altcp_pcb *conn) -{ - if (conn) { - if (conn->fns && conn->fns->dealloc) { - conn->fns->dealloc(conn); - } - memp_free(MEMP_ALTCP_PCB, conn); - } -} - -/** - * @ingroup altcp - * altcp_new_ip6: @ref altcp_new for IPv6 - */ -struct altcp_pcb * -altcp_new_ip6(altcp_allocator_t *allocator) -{ - return altcp_new_ip_type(allocator, IPADDR_TYPE_V6); -} - -/** - * @ingroup altcp - * altcp_new: @ref altcp_new for IPv4 - */ -struct altcp_pcb * -altcp_new(altcp_allocator_t *allocator) -{ - return altcp_new_ip_type(allocator, IPADDR_TYPE_V4); -} - -/** - * @ingroup altcp - * altcp_new_ip_type: called by applications to allocate a new pcb with the help of an - * allocator function. - * - * @param allocator allocator function and argument - * @param ip_type IP version of the pcb (@ref lwip_ip_addr_type) - * @return a new altcp_pcb or NULL on error - */ -struct altcp_pcb * -altcp_new_ip_type(altcp_allocator_t *allocator, u8_t ip_type) -{ - struct altcp_pcb *conn; - if (allocator == NULL) { - /* no allocator given, create a simple TCP connection */ - return altcp_tcp_new_ip_type(ip_type); - } - if (allocator->alloc == NULL) { - /* illegal allocator */ - return NULL; - } - conn = allocator->alloc(allocator->arg, ip_type); - if (conn == NULL) { - /* allocation failed */ - return NULL; - } - return conn; -} - -/** - * @ingroup altcp - * @see tcp_arg() - */ -void -altcp_arg(struct altcp_pcb *conn, void *arg) -{ - if (conn) { - conn->arg = arg; - } -} - -/** - * @ingroup altcp - * @see tcp_accept() - */ -void -altcp_accept(struct altcp_pcb *conn, altcp_accept_fn accept) -{ - if (conn != NULL) { - conn->accept = accept; - } -} - -/** - * @ingroup altcp - * @see tcp_recv() - */ -void -altcp_recv(struct altcp_pcb *conn, altcp_recv_fn recv) -{ - if (conn) { - conn->recv = recv; - } -} - -/** - * @ingroup altcp - * @see tcp_sent() - */ -void -altcp_sent(struct altcp_pcb *conn, altcp_sent_fn sent) -{ - if (conn) { - conn->sent = sent; - } -} - -/** - * @ingroup altcp - * @see tcp_poll() - */ -void -altcp_poll(struct altcp_pcb *conn, altcp_poll_fn poll, u8_t interval) -{ - if (conn) { - conn->poll = poll; - conn->pollinterval = interval; - if (conn->fns && conn->fns->set_poll) { - conn->fns->set_poll(conn, interval); - } - } -} - -/** - * @ingroup altcp - * @see tcp_err() - */ -void -altcp_err(struct altcp_pcb *conn, altcp_err_fn err) -{ - if (conn) { - conn->err = err; - } -} - -/* Generic functions calling the "virtual" ones */ - -/** - * @ingroup altcp - * @see tcp_recved() - */ -void -altcp_recved(struct altcp_pcb *conn, u16_t len) -{ - if (conn && conn->fns && conn->fns->recved) { - conn->fns->recved(conn, len); - } -} - -/** - * @ingroup altcp - * @see tcp_bind() - */ -err_t -altcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port) -{ - if (conn && conn->fns && conn->fns->bind) { - return conn->fns->bind(conn, ipaddr, port); - } - return ERR_VAL; -} - -/** - * @ingroup altcp - * @see tcp_connect() - */ -err_t -altcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected) -{ - if (conn && conn->fns && conn->fns->connect) { - return conn->fns->connect(conn, ipaddr, port, connected); - } - return ERR_VAL; -} - -/** - * @ingroup altcp - * @see tcp_listen_with_backlog_and_err() - */ -struct altcp_pcb * -altcp_listen_with_backlog_and_err(struct altcp_pcb *conn, u8_t backlog, err_t *err) -{ - if (conn && conn->fns && conn->fns->listen) { - return conn->fns->listen(conn, backlog, err); - } - return NULL; -} - -/** - * @ingroup altcp - * @see tcp_abort() - */ -void -altcp_abort(struct altcp_pcb *conn) -{ - if (conn && conn->fns && conn->fns->abort) { - conn->fns->abort(conn); - } -} - -/** - * @ingroup altcp - * @see tcp_close() - */ -err_t -altcp_close(struct altcp_pcb *conn) -{ - if (conn && conn->fns && conn->fns->close) { - return conn->fns->close(conn); - } - return ERR_VAL; -} - -/** - * @ingroup altcp - * @see tcp_shutdown() - */ -err_t -altcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx) -{ - if (conn && conn->fns && conn->fns->shutdown) { - return conn->fns->shutdown(conn, shut_rx, shut_tx); - } - return ERR_VAL; -} - -/** - * @ingroup altcp - * @see tcp_write() - */ -err_t -altcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) -{ - if (conn && conn->fns && conn->fns->write) { - return conn->fns->write(conn, dataptr, len, apiflags); - } - return ERR_VAL; -} - -/** - * @ingroup altcp - * @see tcp_output() - */ -err_t -altcp_output(struct altcp_pcb *conn) -{ - if (conn && conn->fns && conn->fns->output) { - return conn->fns->output(conn); - } - return ERR_VAL; -} - -/** - * @ingroup altcp - * @see tcp_mss() - */ -u16_t -altcp_mss(struct altcp_pcb *conn) -{ - if (conn && conn->fns && conn->fns->mss) { - return conn->fns->mss(conn); - } - return 0; -} - -/** - * @ingroup altcp - * @see tcp_sndbuf() - */ -u16_t -altcp_sndbuf(struct altcp_pcb *conn) -{ - if (conn && conn->fns && conn->fns->sndbuf) { - return conn->fns->sndbuf(conn); - } - return 0; -} - -/** - * @ingroup altcp - * @see tcp_sndqueuelen() - */ -u16_t -altcp_sndqueuelen(struct altcp_pcb *conn) -{ - if (conn && conn->fns && conn->fns->sndqueuelen) { - return conn->fns->sndqueuelen(conn); - } - return 0; -} - -void -altcp_nagle_disable(struct altcp_pcb *conn) -{ - if (conn && conn->fns && conn->fns->nagle_disable) { - conn->fns->nagle_disable(conn); - } -} - -void -altcp_nagle_enable(struct altcp_pcb *conn) -{ - if (conn && conn->fns && conn->fns->nagle_enable) { - conn->fns->nagle_enable(conn); - } -} - -int -altcp_nagle_disabled(struct altcp_pcb *conn) -{ - if (conn && conn->fns && conn->fns->nagle_disabled) { - return conn->fns->nagle_disabled(conn); - } - return 0; -} - -/** - * @ingroup altcp - * @see tcp_setprio() - */ -void -altcp_setprio(struct altcp_pcb *conn, u8_t prio) -{ - if (conn && conn->fns && conn->fns->setprio) { - conn->fns->setprio(conn, prio); - } -} - -err_t -altcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port) -{ - if (conn && conn->fns && conn->fns->addrinfo) { - return conn->fns->addrinfo(conn, local, addr, port); - } - return ERR_VAL; -} - -ip_addr_t * -altcp_get_ip(struct altcp_pcb *conn, int local) -{ - if (conn && conn->fns && conn->fns->getip) { - return conn->fns->getip(conn, local); - } - return NULL; -} - -u16_t -altcp_get_port(struct altcp_pcb *conn, int local) -{ - if (conn && conn->fns && conn->fns->getport) { - return conn->fns->getport(conn, local); - } - return 0; -} - -#ifdef LWIP_DEBUG -enum tcp_state -altcp_dbg_get_tcp_state(struct altcp_pcb *conn) -{ - if (conn && conn->fns && conn->fns->dbg_get_tcp_state) { - return conn->fns->dbg_get_tcp_state(conn); - } - return CLOSED; -} -#endif - -/* Default implementations for the "virtual" functions */ - -void -altcp_default_set_poll(struct altcp_pcb *conn, u8_t interval) -{ - if (conn && conn->inner_conn) { - altcp_poll(conn->inner_conn, conn->poll, interval); - } -} - -void -altcp_default_recved(struct altcp_pcb *conn, u16_t len) -{ - if (conn && conn->inner_conn) { - altcp_recved(conn->inner_conn, len); - } -} - -err_t -altcp_default_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port) -{ - if (conn && conn->inner_conn) { - return altcp_bind(conn->inner_conn, ipaddr, port); - } - return ERR_VAL; -} - -err_t -altcp_default_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx) -{ - if (conn) { - if (shut_rx && shut_tx && conn->fns && conn->fns->close) { - /* default shutdown for both sides is close */ - return conn->fns->close(conn); - } - if (conn->inner_conn) { - return altcp_shutdown(conn->inner_conn, shut_rx, shut_tx); - } - } - return ERR_VAL; -} - -err_t -altcp_default_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) -{ - if (conn && conn->inner_conn) { - return altcp_write(conn->inner_conn, dataptr, len, apiflags); - } - return ERR_VAL; -} - -err_t -altcp_default_output(struct altcp_pcb *conn) -{ - if (conn && conn->inner_conn) { - return altcp_output(conn->inner_conn); - } - return ERR_VAL; -} - -u16_t -altcp_default_mss(struct altcp_pcb *conn) -{ - if (conn && conn->inner_conn) { - return altcp_mss(conn->inner_conn); - } - return 0; -} - -u16_t -altcp_default_sndbuf(struct altcp_pcb *conn) -{ - if (conn && conn->inner_conn) { - return altcp_sndbuf(conn->inner_conn); - } - return 0; -} - -u16_t -altcp_default_sndqueuelen(struct altcp_pcb *conn) -{ - if (conn && conn->inner_conn) { - return altcp_sndqueuelen(conn->inner_conn); - } - return 0; -} - -void -altcp_default_nagle_disable(struct altcp_pcb *conn) -{ - if (conn && conn->inner_conn) { - altcp_nagle_disable(conn->inner_conn); - } -} - -void -altcp_default_nagle_enable(struct altcp_pcb *conn) -{ - if (conn && conn->inner_conn) { - altcp_nagle_enable(conn->inner_conn); - } -} - -int -altcp_default_nagle_disabled(struct altcp_pcb *conn) -{ - if (conn && conn->inner_conn) { - return altcp_nagle_disabled(conn->inner_conn); - } - return 0; -} - -void -altcp_default_setprio(struct altcp_pcb *conn, u8_t prio) -{ - if (conn && conn->inner_conn) { - altcp_setprio(conn->inner_conn, prio); - } -} - -void -altcp_default_dealloc(struct altcp_pcb *conn) -{ - LWIP_UNUSED_ARG(conn); - /* nothing to do */ -} - -err_t -altcp_default_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port) -{ - if (conn && conn->inner_conn) { - return altcp_get_tcp_addrinfo(conn->inner_conn, local, addr, port); - } - return ERR_VAL; -} - -ip_addr_t * -altcp_default_get_ip(struct altcp_pcb *conn, int local) -{ - if (conn && conn->inner_conn) { - return altcp_get_ip(conn->inner_conn, local); - } - return NULL; -} - -u16_t -altcp_default_get_port(struct altcp_pcb *conn, int local) -{ - if (conn && conn->inner_conn) { - return altcp_get_port(conn->inner_conn, local); - } - return 0; -} - -#ifdef LWIP_DEBUG -enum tcp_state -altcp_default_dbg_get_tcp_state(struct altcp_pcb *conn) -{ - if (conn && conn->inner_conn) { - return altcp_dbg_get_tcp_state(conn->inner_conn); - } - return CLOSED; -} -#endif - - -#endif /* LWIP_ALTCP */ diff --git a/core/c/core/altcp_alloc.c b/core/c/core/altcp_alloc.c deleted file mode 100755 index 8c2390e..0000000 --- a/core/c/core/altcp_alloc.c +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @file - * Application layered TCP connection API (to be used from TCPIP thread)\n - * This interface mimics the tcp callback API to the application while preventing - * direct linking (much like virtual functions). - * This way, an application can make use of other application layer protocols - * on top of TCP without knowing the details (e.g. TLS, proxy connection). - * - * This file contains allocation implementation that combine several layers. - */ - -/* - * Copyright (c) 2017 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ - -#include "lwip/opt.h" - -#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/altcp.h" -#include "lwip/altcp_tcp.h" -#include "lwip/altcp_tls.h" -#include "lwip/priv/altcp_priv.h" -#include "lwip/mem.h" - -#include - -#if LWIP_ALTCP_TLS - -/** This standard allocator function creates an altcp pcb for - * TLS over TCP */ -struct altcp_pcb * -altcp_tls_new(struct altcp_tls_config *config, u8_t ip_type) -{ - struct altcp_pcb *inner_conn, *ret; - LWIP_UNUSED_ARG(ip_type); - - inner_conn = altcp_tcp_new_ip_type(ip_type); - if (inner_conn == NULL) { - return NULL; - } - ret = altcp_tls_wrap(config, inner_conn); - if (ret == NULL) { - altcp_close(inner_conn); - } - return ret; -} - -/** This standard allocator function creates an altcp pcb for - * TLS over TCP */ -struct altcp_pcb * -altcp_tls_alloc(void *arg, u8_t ip_type) -{ - return altcp_tls_new((struct altcp_tls_config *)arg, ip_type); -} - -#endif /* LWIP_ALTCP_TLS */ - -#endif /* LWIP_ALTCP */ diff --git a/core/c/core/altcp_tcp.c b/core/c/core/altcp_tcp.c deleted file mode 100755 index f5b8e84..0000000 --- a/core/c/core/altcp_tcp.c +++ /dev/null @@ -1,543 +0,0 @@ -/** - * @file - * Application layered TCP connection API (to be used from TCPIP thread)\n - * This interface mimics the tcp callback API to the application while preventing - * direct linking (much like virtual functions). - * This way, an application can make use of other application layer protocols - * on top of TCP without knowing the details (e.g. TLS, proxy connection). - * - * This file contains the base implementation calling into tcp. - */ - -/* - * Copyright (c) 2017 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ - -#include "lwip/opt.h" - -#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/altcp.h" -#include "lwip/altcp_tcp.h" -#include "lwip/priv/altcp_priv.h" -#include "lwip/tcp.h" -#include "lwip/mem.h" - -#include - -#define ALTCP_TCP_ASSERT_CONN(conn) do { \ - LWIP_ASSERT("conn->inner_conn == NULL", (conn)->inner_conn == NULL); \ - LWIP_UNUSED_ARG(conn); /* for LWIP_NOASSERT */ } while(0) -#define ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb) do { \ - LWIP_ASSERT("pcb mismatch", (conn)->state == tpcb); \ - LWIP_UNUSED_ARG(tpcb); /* for LWIP_NOASSERT */ \ - ALTCP_TCP_ASSERT_CONN(conn); } while(0) - - -/* Variable prototype, the actual declaration is at the end of this file - since it contains pointers to static functions declared here */ -extern const struct altcp_functions altcp_tcp_functions; - -static void altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb); - -/* callback functions for TCP */ -static err_t -altcp_tcp_accept(void *arg, struct tcp_pcb *new_tpcb, err_t err) -{ - struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg; - if (listen_conn && listen_conn->accept) { - /* create a new altcp_conn to pass to the next 'accept' callback */ - struct altcp_pcb *new_conn = altcp_alloc(); - if (new_conn == NULL) { - return ERR_MEM; - } - altcp_tcp_setup(new_conn, new_tpcb); - return listen_conn->accept(listen_conn->arg, new_conn, err); - } - return ERR_ARG; -} - -static err_t -altcp_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) -{ - struct altcp_pcb *conn = (struct altcp_pcb *)arg; - if (conn) { - ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb); - if (conn->connected) { - return conn->connected(conn->arg, conn, err); - } - } - return ERR_OK; -} - -static err_t -altcp_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) -{ - struct altcp_pcb *conn = (struct altcp_pcb *)arg; - if (conn) { - ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb); - if (conn->recv) { - return conn->recv(conn->arg, conn, p, err); - } - } - if (p != NULL) { - /* prevent memory leaks */ - pbuf_free(p); - } - return ERR_OK; -} - -static err_t -altcp_tcp_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) -{ - struct altcp_pcb *conn = (struct altcp_pcb *)arg; - if (conn) { - ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb); - if (conn->sent) { - return conn->sent(conn->arg, conn, len); - } - } - return ERR_OK; -} - -static err_t -altcp_tcp_poll(void *arg, struct tcp_pcb *tpcb) -{ - struct altcp_pcb *conn = (struct altcp_pcb *)arg; - if (conn) { - ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb); - if (conn->poll) { - return conn->poll(conn->arg, conn); - } - } - return ERR_OK; -} - -static void -altcp_tcp_err(void *arg, err_t err) -{ - struct altcp_pcb *conn = (struct altcp_pcb *)arg; - if (conn) { - conn->state = NULL; /* already freed */ - if (conn->err) { - conn->err(conn->arg, err); - } - altcp_free(conn); - } -} - -/* setup functions */ - -static void -altcp_tcp_remove_callbacks(struct tcp_pcb *tpcb) -{ - tcp_arg(tpcb, NULL); - tcp_recv(tpcb, NULL); - tcp_sent(tpcb, NULL); - tcp_err(tpcb, NULL); - tcp_poll(tpcb, NULL, tpcb->pollinterval); -} - -static void -altcp_tcp_setup_callbacks(struct altcp_pcb *conn, struct tcp_pcb *tpcb) -{ - tcp_arg(tpcb, conn); - tcp_recv(tpcb, altcp_tcp_recv); - tcp_sent(tpcb, altcp_tcp_sent); - tcp_err(tpcb, altcp_tcp_err); - /* tcp_poll is set when interval is set by application */ - /* listen is set totally different :-) */ -} - -static void -altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb) -{ - altcp_tcp_setup_callbacks(conn, tpcb); - conn->state = tpcb; - conn->fns = &altcp_tcp_functions; -} - -struct altcp_pcb * -altcp_tcp_new_ip_type(u8_t ip_type) -{ - /* Allocate the tcp pcb first to invoke the priority handling code - if we're out of pcbs */ - struct tcp_pcb *tpcb = tcp_new_ip_type(ip_type); - if (tpcb != NULL) { - struct altcp_pcb *ret = altcp_alloc(); - if (ret != NULL) { - altcp_tcp_setup(ret, tpcb); - return ret; - } else { - /* altcp_pcb allocation failed -> free the tcp_pcb too */ - tcp_close(tpcb); - } - } - return NULL; -} - -/** altcp_tcp allocator function fitting to @ref altcp_allocator_t / @ref altcp_new. -* -* arg pointer is not used for TCP. -*/ -struct altcp_pcb * -altcp_tcp_alloc(void *arg, u8_t ip_type) -{ - LWIP_UNUSED_ARG(arg); - return altcp_tcp_new_ip_type(ip_type); -} - -struct altcp_pcb * -altcp_tcp_wrap(struct tcp_pcb *tpcb) -{ - if (tpcb != NULL) { - struct altcp_pcb *ret = altcp_alloc(); - if (ret != NULL) { - altcp_tcp_setup(ret, tpcb); - return ret; - } - } - return NULL; -} - - -/* "virtual" functions calling into tcp */ -static void -altcp_tcp_set_poll(struct altcp_pcb *conn, u8_t interval) -{ - if (conn != NULL) { - struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; - ALTCP_TCP_ASSERT_CONN(conn); - tcp_poll(pcb, altcp_tcp_poll, interval); - } -} - -static void -altcp_tcp_recved(struct altcp_pcb *conn, u16_t len) -{ - if (conn != NULL) { - struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; - ALTCP_TCP_ASSERT_CONN(conn); - tcp_recved(pcb, len); - } -} - -static err_t -altcp_tcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port) -{ - struct tcp_pcb *pcb; - if (conn == NULL) { - return ERR_VAL; - } - ALTCP_TCP_ASSERT_CONN(conn); - pcb = (struct tcp_pcb *)conn->state; - return tcp_bind(pcb, ipaddr, port); -} - -static err_t -altcp_tcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected) -{ - struct tcp_pcb *pcb; - if (conn == NULL) { - return ERR_VAL; - } - ALTCP_TCP_ASSERT_CONN(conn); - conn->connected = connected; - pcb = (struct tcp_pcb *)conn->state; - return tcp_connect(pcb, ipaddr, port, altcp_tcp_connected); -} - -static struct altcp_pcb * -altcp_tcp_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err) -{ - struct tcp_pcb *pcb; - struct tcp_pcb *lpcb; - if (conn == NULL) { - return NULL; - } - ALTCP_TCP_ASSERT_CONN(conn); - pcb = (struct tcp_pcb *)conn->state; - lpcb = tcp_listen_with_backlog_and_err(pcb, backlog, err); - if (lpcb != NULL) { - conn->state = lpcb; - tcp_accept(lpcb, altcp_tcp_accept); - return conn; - } - return NULL; -} - -static void -altcp_tcp_abort(struct altcp_pcb *conn) -{ - if (conn != NULL) { - struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; - ALTCP_TCP_ASSERT_CONN(conn); - if (pcb) { - tcp_abort(pcb); - } - } -} - -static err_t -altcp_tcp_close(struct altcp_pcb *conn) -{ - struct tcp_pcb *pcb; - if (conn == NULL) { - return ERR_VAL; - } - ALTCP_TCP_ASSERT_CONN(conn); - pcb = (struct tcp_pcb *)conn->state; - if (pcb) { - err_t err; - tcp_poll_fn oldpoll = pcb->poll; - altcp_tcp_remove_callbacks(pcb); - err = tcp_close(pcb); - if (err != ERR_OK) { - /* not closed, set up all callbacks again */ - altcp_tcp_setup_callbacks(conn, pcb); - /* poll callback is not included in the above */ - tcp_poll(pcb, oldpoll, pcb->pollinterval); - return err; - } - conn->state = NULL; /* unsafe to reference pcb after tcp_close(). */ - } - altcp_free(conn); - return ERR_OK; -} - -static err_t -altcp_tcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx) -{ - struct tcp_pcb *pcb; - if (conn == NULL) { - return ERR_VAL; - } - ALTCP_TCP_ASSERT_CONN(conn); - pcb = (struct tcp_pcb *)conn->state; - return tcp_shutdown(pcb, shut_rx, shut_tx); -} - -static err_t -altcp_tcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) -{ - struct tcp_pcb *pcb; - if (conn == NULL) { - return ERR_VAL; - } - ALTCP_TCP_ASSERT_CONN(conn); - pcb = (struct tcp_pcb *)conn->state; - return tcp_write(pcb, dataptr, len, apiflags); -} - -static err_t -altcp_tcp_output(struct altcp_pcb *conn) -{ - struct tcp_pcb *pcb; - if (conn == NULL) { - return ERR_VAL; - } - ALTCP_TCP_ASSERT_CONN(conn); - pcb = (struct tcp_pcb *)conn->state; - return tcp_output(pcb); -} - -static u16_t -altcp_tcp_mss(struct altcp_pcb *conn) -{ - struct tcp_pcb *pcb; - if (conn == NULL) { - return 0; - } - ALTCP_TCP_ASSERT_CONN(conn); - pcb = (struct tcp_pcb *)conn->state; - return tcp_mss(pcb); -} - -static u16_t -altcp_tcp_sndbuf(struct altcp_pcb *conn) -{ - struct tcp_pcb *pcb; - if (conn == NULL) { - return 0; - } - ALTCP_TCP_ASSERT_CONN(conn); - pcb = (struct tcp_pcb *)conn->state; - return tcp_sndbuf(pcb); -} - -static u16_t -altcp_tcp_sndqueuelen(struct altcp_pcb *conn) -{ - struct tcp_pcb *pcb; - if (conn == NULL) { - return 0; - } - ALTCP_TCP_ASSERT_CONN(conn); - pcb = (struct tcp_pcb *)conn->state; - return tcp_sndqueuelen(pcb); -} - -static void -altcp_tcp_nagle_disable(struct altcp_pcb *conn) -{ - if (conn && conn->state) { - struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; - ALTCP_TCP_ASSERT_CONN(conn); - tcp_nagle_disable(pcb); - } -} - -static void -altcp_tcp_nagle_enable(struct altcp_pcb *conn) -{ - if (conn && conn->state) { - struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; - ALTCP_TCP_ASSERT_CONN(conn); - tcp_nagle_enable(pcb); - } -} - -static int -altcp_tcp_nagle_disabled(struct altcp_pcb *conn) -{ - if (conn && conn->state) { - struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; - ALTCP_TCP_ASSERT_CONN(conn); - return tcp_nagle_disabled(pcb); - } - return 0; -} - -static void -altcp_tcp_setprio(struct altcp_pcb *conn, u8_t prio) -{ - if (conn != NULL) { - struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; - ALTCP_TCP_ASSERT_CONN(conn); - tcp_setprio(pcb, prio); - } -} - -static void -altcp_tcp_dealloc(struct altcp_pcb *conn) -{ - LWIP_UNUSED_ARG(conn); - ALTCP_TCP_ASSERT_CONN(conn); - /* no private state to clean up */ -} - -static err_t -altcp_tcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port) -{ - if (conn) { - struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; - ALTCP_TCP_ASSERT_CONN(conn); - return tcp_tcp_get_tcp_addrinfo(pcb, local, addr, port); - } - return ERR_VAL; -} - -static ip_addr_t * -altcp_tcp_get_ip(struct altcp_pcb *conn, int local) -{ - if (conn) { - struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; - ALTCP_TCP_ASSERT_CONN(conn); - if (pcb) { - if (local) { - return &pcb->local_ip; - } else { - return &pcb->remote_ip; - } - } - } - return NULL; -} - -static u16_t -altcp_tcp_get_port(struct altcp_pcb *conn, int local) -{ - if (conn) { - struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; - ALTCP_TCP_ASSERT_CONN(conn); - if (pcb) { - if (local) { - return pcb->local_port; - } else { - return pcb->remote_port; - } - } - } - return 0; -} - -#ifdef LWIP_DEBUG -static enum tcp_state -altcp_tcp_dbg_get_tcp_state(struct altcp_pcb *conn) -{ - if (conn) { - struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; - ALTCP_TCP_ASSERT_CONN(conn); - if (pcb) { - return pcb->state; - } - } - return CLOSED; -} -#endif -const struct altcp_functions altcp_tcp_functions = { - altcp_tcp_set_poll, - altcp_tcp_recved, - altcp_tcp_bind, - altcp_tcp_connect, - altcp_tcp_listen, - altcp_tcp_abort, - altcp_tcp_close, - altcp_tcp_shutdown, - altcp_tcp_write, - altcp_tcp_output, - altcp_tcp_mss, - altcp_tcp_sndbuf, - altcp_tcp_sndqueuelen, - altcp_tcp_nagle_disable, - altcp_tcp_nagle_enable, - altcp_tcp_nagle_disabled, - altcp_tcp_setprio, - altcp_tcp_dealloc, - altcp_tcp_get_tcp_addrinfo, - altcp_tcp_get_ip, - altcp_tcp_get_port -#ifdef LWIP_DEBUG - , altcp_tcp_dbg_get_tcp_state -#endif -}; - -#endif /* LWIP_ALTCP */ diff --git a/core/c/core/def.c b/core/c/core/def.c deleted file mode 100755 index 004a528..0000000 --- a/core/c/core/def.c +++ /dev/null @@ -1,240 +0,0 @@ -/** - * @file - * Common functions used throughout the stack. - * - * These are reference implementations of the byte swapping functions. - * Again with the aim of being simple, correct and fully portable. - * Byte swapping is the second thing you would want to optimize. You will - * need to port it to your architecture and in your cc.h: - * - * \#define lwip_htons(x) your_htons - * \#define lwip_htonl(x) your_htonl - * - * Note lwip_ntohs() and lwip_ntohl() are merely references to the htonx counterparts. - * - * If you \#define them to htons() and htonl(), you should - * \#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from - * defining htonx/ntohx compatibility macros. - - * @defgroup sys_nonstandard Non-standard functions - * @ingroup sys_layer - * lwIP provides default implementations for non-standard functions. - * These can be mapped to OS functions to reduce code footprint if desired. - * All defines related to this section must not be placed in lwipopts.h, - * but in arch/cc.h! - * These options cannot be \#defined in lwipopts.h since they are not options - * of lwIP itself, but options of the lwIP port to your system. - */ - -/* - * 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" - -#include - -#if BYTE_ORDER == LITTLE_ENDIAN - -#if !defined(lwip_htons) -/** - * 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 PP_HTONS(n); -} -#endif /* lwip_htons */ - -#if !defined(lwip_htonl) -/** - * 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 PP_HTONL(n); -} -#endif /* lwip_htonl */ - -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -#ifndef lwip_strnstr -/** - * @ingroup sys_nonstandard - * lwIP default implementation for strnstr() non-standard function. - * This can be \#defined to strnstr() depending on your platform port. - */ -char * -lwip_strnstr(const char *buffer, const char *token, size_t n) -{ - const char *p; - size_t tokenlen = strlen(token); - if (tokenlen == 0) { - return LWIP_CONST_CAST(char *, buffer); - } - for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) { - if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) { - return LWIP_CONST_CAST(char *, p); - } - } - return NULL; -} -#endif - -#ifndef lwip_stricmp -/** - * @ingroup sys_nonstandard - * lwIP default implementation for stricmp() non-standard function. - * This can be \#defined to stricmp() depending on your platform port. - */ -int -lwip_stricmp(const char *str1, const char *str2) -{ - char c1, c2; - - do { - c1 = *str1++; - c2 = *str2++; - if (c1 != c2) { - char c1_upc = c1 | 0x20; - if ((c1_upc >= 'a') && (c1_upc <= 'z')) { - /* characters are not equal an one is in the alphabet range: - downcase both chars and check again */ - char c2_upc = c2 | 0x20; - if (c1_upc != c2_upc) { - /* still not equal */ - /* don't care for < or > */ - return 1; - } - } else { - /* characters are not equal but none is in the alphabet range */ - return 1; - } - } - } while (c1 != 0); - return 0; -} -#endif - -#ifndef lwip_strnicmp -/** - * @ingroup sys_nonstandard - * lwIP default implementation for strnicmp() non-standard function. - * This can be \#defined to strnicmp() depending on your platform port. - */ -int -lwip_strnicmp(const char *str1, const char *str2, size_t len) -{ - char c1, c2; - - do { - c1 = *str1++; - c2 = *str2++; - if (c1 != c2) { - char c1_upc = c1 | 0x20; - if ((c1_upc >= 'a') && (c1_upc <= 'z')) { - /* characters are not equal an one is in the alphabet range: - downcase both chars and check again */ - char c2_upc = c2 | 0x20; - if (c1_upc != c2_upc) { - /* still not equal */ - /* don't care for < or > */ - return 1; - } - } else { - /* characters are not equal but none is in the alphabet range */ - return 1; - } - } - len--; - } while ((len != 0) && (c1 != 0)); - return 0; -} -#endif - -#ifndef lwip_itoa -/** - * @ingroup sys_nonstandard - * lwIP default implementation for itoa() non-standard function. - * This can be \#defined to itoa() or snprintf(result, bufsize, "%d", number) depending on your platform port. - */ -void -lwip_itoa(char *result, size_t bufsize, int number) -{ - char *res = result; - char *tmp = result + bufsize - 1; - int n = (number >= 0) ? number : -number; - - /* handle invalid bufsize */ - if (bufsize < 2) { - if (bufsize == 1) { - *result = 0; - } - return; - } - - /* First, add sign */ - if (number < 0) { - *res++ = '-'; - } - /* Then create the string from the end and stop if buffer full, - and ensure output string is zero terminated */ - *tmp = 0; - while ((n != 0) && (tmp > res)) { - char val = (char)('0' + (n % 10)); - tmp--; - *tmp = val; - n = n / 10; - } - if (n) { - /* buffer is too small */ - *result = 0; - return; - } - if (*tmp == 0) { - /* Nothing added? */ - *res++ = '0'; - *res++ = 0; - return; - } - /* move from temporary buffer to output buffer (sign is not moved) */ - memmove(res, tmp, (size_t)((result + bufsize) - tmp)); -} -#endif diff --git a/core/c/core/dns.c b/core/c/core/dns.c deleted file mode 100755 index 737b339..0000000 --- a/core/c/core/dns.c +++ /dev/null @@ -1,1631 +0,0 @@ -/** - * @file - * DNS - host name to IP address resolver. - * - * @defgroup dns DNS - * @ingroup callbackstyle_api - * - * Implements a DNS host name to IP address resolver. - * - * 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). - * - * Multicast DNS queries are supported for names ending on ".local". - * However, only "One-Shot Multicast DNS Queries" are supported (RFC 6762 - * chapter 5.1), this is not a fully compliant implementation of continuous - * mDNS querying! - * - * All functions must be called from TCPIP thread. - * - * @see DNS_MAX_SERVERS - * @see LWIP_DHCP_MAX_DNS_SERVERS - * @see @ref netconn_common for thread-safe access. - */ - -/* - * Port to lwIP from uIP - * by Jim Pettinato April 2007 - * - * security fixes and more by Simon Goldschmidt - * - * 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. - */ - -/*----------------------------------------------------------------------------- - * 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 */ -/** @todo: one-shot mDNS: dual-stack fallback to another IP version */ - -/*----------------------------------------------------------------------------- - * Includes - *----------------------------------------------------------------------------*/ - -#include "lwip/opt.h" - -#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/def.h" -#include "lwip/udp.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/dns.h" -#include "lwip/prot/dns.h" - -#include - -/** Random generator function to create random TXIDs and source ports for queries */ -#ifndef DNS_RAND_TXID -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_XID) != 0) -#define DNS_RAND_TXID LWIP_RAND -#else -static u16_t dns_txid; -#define DNS_RAND_TXID() (++dns_txid) -#endif -#endif - -/** Limits the source port to be >= 1024 by default */ -#ifndef DNS_PORT_ALLOWED -#define DNS_PORT_ALLOWED(port) ((port) >= 1024) -#endif - -/** DNS resource record max. TTL (one week as default) */ -#ifndef DNS_MAX_TTL -#define DNS_MAX_TTL 604800 -#elif DNS_MAX_TTL > 0x7FFFFFFF -#error DNS_MAX_TTL must be a positive 32-bit value -#endif - -#if DNS_TABLE_SIZE > 255 -#error DNS_TABLE_SIZE must fit into an u8_t -#endif -#if DNS_MAX_SERVERS > 255 -#error DNS_MAX_SERVERS must fit into an u8_t -#endif - -/* The number of parallel requests (i.e. calls to dns_gethostbyname - * that cannot be answered from the DNS table. - * This is set to the table size by default. - */ -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) -#ifndef DNS_MAX_REQUESTS -#define DNS_MAX_REQUESTS DNS_TABLE_SIZE -#else -#if DNS_MAX_REQUESTS > 255 -#error DNS_MAX_REQUESTS must fit into an u8_t -#endif -#endif -#else -/* In this configuration, both arrays have to have the same size and are used - * like one entry (used/free) */ -#define DNS_MAX_REQUESTS DNS_TABLE_SIZE -#endif - -/* The number of UDP source ports used in parallel */ -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) -#ifndef DNS_MAX_SOURCE_PORTS -#define DNS_MAX_SOURCE_PORTS DNS_MAX_REQUESTS -#else -#if DNS_MAX_SOURCE_PORTS > 255 -#error DNS_MAX_SOURCE_PORTS must fit into an u8_t -#endif -#endif -#else -#ifdef DNS_MAX_SOURCE_PORTS -#undef DNS_MAX_SOURCE_PORTS -#endif -#define DNS_MAX_SOURCE_PORTS 1 -#endif - -#if LWIP_IPV4 && LWIP_IPV6 -#define LWIP_DNS_ADDRTYPE_IS_IPV6(t) (((t) == LWIP_DNS_ADDRTYPE_IPV6_IPV4) || ((t) == LWIP_DNS_ADDRTYPE_IPV6)) -#define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) (IP_IS_V6_VAL(ip) ? LWIP_DNS_ADDRTYPE_IS_IPV6(t) : (!LWIP_DNS_ADDRTYPE_IS_IPV6(t))) -#define LWIP_DNS_ADDRTYPE_ARG(x) , x -#define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) x -#define LWIP_DNS_SET_ADDRTYPE(x, y) do { x = y; } while(0) -#else -#if LWIP_IPV6 -#define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 1 -#else -#define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 0 -#endif -#define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) 1 -#define LWIP_DNS_ADDRTYPE_ARG(x) -#define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) 0 -#define LWIP_DNS_SET_ADDRTYPE(x, y) -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - -#if LWIP_DNS_SUPPORT_MDNS_QUERIES -#define LWIP_DNS_ISMDNS_ARG(x) , x -#else -#define LWIP_DNS_ISMDNS_ARG(x) -#endif - -/** 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 -/* maximum allowed size for the struct due to non-packed */ -#define SIZEOF_DNS_ANSWER_ASSERT 12 - -/* DNS table entry states */ -typedef enum { - DNS_STATE_UNUSED = 0, - DNS_STATE_NEW = 1, - DNS_STATE_ASKING = 2, - DNS_STATE_DONE = 3 -} dns_state_enum_t; - -/** DNS table entry */ -struct dns_table_entry { - u32_t ttl; - ip_addr_t ipaddr; - u16_t txid; - u8_t state; - u8_t server_idx; - u8_t tmr; - u8_t retries; - u8_t seqno; -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) - u8_t pcb_idx; -#endif - char name[DNS_MAX_NAME_LENGTH]; -#if LWIP_IPV4 && LWIP_IPV6 - u8_t reqaddrtype; -#endif /* LWIP_IPV4 && LWIP_IPV6 */ -#if LWIP_DNS_SUPPORT_MDNS_QUERIES - u8_t is_mdns; -#endif -}; - -/** DNS request table entry: used when dns_gehostbyname cannot answer the - * request from the DNS table */ -struct dns_req_entry { - /* pointer to callback on DNS query done */ - dns_found_callback found; - /* argument passed to the callback function */ - void *arg; -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) - u8_t dns_table_idx; -#endif -#if LWIP_IPV4 && LWIP_IPV6 - u8_t reqaddrtype; -#endif /* LWIP_IPV4 && LWIP_IPV6 */ -}; - -#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(void); -static err_t dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)); -#endif /* DNS_LOCAL_HOSTLIST */ - - -/* forward declarations */ -static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); -static void dns_check_entries(void); -static void dns_call_found(u8_t idx, ip_addr_t *addr); - -/*----------------------------------------------------------------------------- - * Globals - *----------------------------------------------------------------------------*/ - -/* DNS variables */ -static struct udp_pcb *dns_pcbs[DNS_MAX_SOURCE_PORTS]; -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) -static u8_t dns_last_pcb_idx; -#endif -static u8_t dns_seqno; -static struct dns_table_entry dns_table[DNS_TABLE_SIZE]; -static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS]; -static ip_addr_t dns_servers[DNS_MAX_SERVERS]; - -#if LWIP_IPV4 -const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT; -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 -const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT; -#endif /* LWIP_IPV6 */ - -/** - * Initialize the resolver: set up the UDP pcb and configure the default server - * (if DNS_SERVER_ADDRESS is set). - */ -void -dns_init(void) -{ -#ifdef DNS_SERVER_ADDRESS - /* initialize default DNS server address */ - ip_addr_t dnsserver; - DNS_SERVER_ADDRESS(&dnsserver); - dns_setserver(0, &dnsserver); -#endif /* DNS_SERVER_ADDRESS */ - - LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY", - sizeof(struct dns_query) == SIZEOF_DNS_QUERY); - LWIP_ASSERT("sanity check SIZEOF_DNS_ANSWER", - sizeof(struct dns_answer) <= SIZEOF_DNS_ANSWER_ASSERT); - - LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); - - /* if dns client not yet initialized... */ -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0) - if (dns_pcbs[0] == NULL) { - dns_pcbs[0] = udp_new_ip_type(IPADDR_TYPE_ANY); - LWIP_ASSERT("dns_pcbs[0] != NULL", dns_pcbs[0] != 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_pcbs[0], IP_ANY_TYPE, 0); - udp_recv(dns_pcbs[0], dns_recv, NULL); - } -#endif - -#if DNS_LOCAL_HOSTLIST - dns_init_local(); -#endif -} - -/** - * @ingroup dns - * 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 -dns_setserver(u8_t numdns, const ip_addr_t *dnsserver) -{ - if (numdns < DNS_MAX_SERVERS) { - if (dnsserver != NULL) { - dns_servers[numdns] = (*dnsserver); - } else { - dns_servers[numdns] = *IP_ADDR_ANY; - } - } -} - -/** - * @ingroup dns - * 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. - */ -const ip_addr_t * -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 -dns_tmr(void) -{ - LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n")); - dns_check_entries(); -} - -#if DNS_LOCAL_HOSTLIST -static void -dns_init_local(void) -{ -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) - size_t 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 < LWIP_ARRAYSIZE(local_hostlist_init); i++) { - struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; - LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL); - namelen = strlen(init_entry->name); - LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); - entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); - LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); - if (entry != NULL) { - char *entry_name = (char *)entry + sizeof(struct local_hostlist_entry); - MEMCPY(entry_name, init_entry->name, namelen); - entry_name[namelen] = 0; - entry->name = entry_name; - 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) */ -} - -/** - * @ingroup dns - * Iterate the local host-list for a hostname. - * - * @param iterator_fn a function that is called for every entry in the local host-list - * @param iterator_arg 3rd argument passed to iterator_fn - * @return the number of entries in the local host-list - */ -size_t -dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg) -{ - size_t i; -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC - struct local_hostlist_entry *entry = local_hostlist_dynamic; - i = 0; - while (entry != NULL) { - if (iterator_fn != NULL) { - iterator_fn(entry->name, &entry->addr, iterator_arg); - } - i++; - entry = entry->next; - } -#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) { - if (iterator_fn != NULL) { - iterator_fn(local_hostlist_static[i].name, &local_hostlist_static[i].addr, iterator_arg); - } - } -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - return i; -} - -/** - * @ingroup dns - * Scans the local host-list for a hostname. - * - * @param hostname Hostname to look for in the local host-list - * @param addr the first IP address for the hostname in the local host-list or - * IPADDR_NONE if not found. - * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 (ATTENTION: no fallback here!) - * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 (ATTENTION: no fallback here!) - * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only - * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only - * @return ERR_OK if found, ERR_ARG if not found - */ -err_t -dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype) -{ - LWIP_UNUSED_ARG(dns_addrtype); - return dns_lookup_local(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)); -} - -/* Internal implementation for dns_local_lookup and dns_lookup */ -static err_t -dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) -{ -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC - struct local_hostlist_entry *entry = local_hostlist_dynamic; - while (entry != NULL) { - if ((lwip_stricmp(entry->name, hostname) == 0) && - LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, entry->addr)) { - if (addr) { - ip_addr_copy(*addr, entry->addr); - } - return ERR_OK; - } - entry = entry->next; - } -#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - size_t i; - for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) { - if ((lwip_stricmp(local_hostlist_static[i].name, hostname) == 0) && - LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, local_hostlist_static[i].addr)) { - if (addr) { - ip_addr_copy(*addr, local_hostlist_static[i].addr); - } - return ERR_OK; - } - } -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - return ERR_ARG; -} - -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC -/** - * @ingroup dns - * Remove all entries from the local host-list for a specific hostname - * and/or IP address - * - * @param hostname hostname for which entries shall be removed from the local - * host-list - * @param addr address for which entries shall be removed from the local host-list - * @return the number of removed entries - */ -int -dns_local_removehost(const char *hostname, const ip_addr_t *addr) -{ - int removed = 0; - struct local_hostlist_entry *entry = local_hostlist_dynamic; - struct local_hostlist_entry *last_entry = NULL; - while (entry != NULL) { - if (((hostname == NULL) || !lwip_stricmp(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; -} - -/** - * @ingroup dns - * Add a hostname/IP address pair to the local host-list. - * Duplicates are not checked. - * - * @param hostname hostname of the new entry - * @param addr IP address of the new entry - * @return ERR_OK if succeeded or ERR_MEM on memory error - */ -err_t -dns_local_addhost(const char *hostname, const ip_addr_t *addr) -{ - struct local_hostlist_entry *entry; - size_t namelen; - char *entry_name; - LWIP_ASSERT("invalid host name (NULL)", hostname != NULL); - namelen = strlen(hostname); - LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); - entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); - if (entry == NULL) { - return ERR_MEM; - } - entry_name = (char *)entry + sizeof(struct local_hostlist_entry); - MEMCPY(entry_name, hostname, namelen); - entry_name[namelen] = 0; - entry->name = entry_name; - 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 */ - -/** - * @ingroup dns - * 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 - * @param addr 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. - * @return ERR_OK if found, ERR_ARG if not found - */ -static err_t -dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) -{ - u8_t i; -#if DNS_LOCAL_HOSTLIST - if (dns_lookup_local(name, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { - return ERR_OK; - } -#endif /* DNS_LOCAL_HOSTLIST */ -#ifdef DNS_LOOKUP_LOCAL_EXTERN - if (DNS_LOOKUP_LOCAL_EXTERN(name, addr, LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(dns_addrtype)) == ERR_OK) { - return ERR_OK; - } -#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) && - (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0) && - LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); - ip_addr_debug_print_val(DNS_DEBUG, dns_table[i].ipaddr); - LWIP_DEBUGF(DNS_DEBUG, ("\n")); - if (addr) { - ip_addr_copy(*addr, dns_table[i].ipaddr); - } - return ERR_OK; - } - } - - return ERR_ARG; -} - -/** - * 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). - * - * For now, this function compares case-insensitive to cope with all kinds of - * servers. This also means that "dns 0x20 bit encoding" must be checked - * externally, if we want to implement it. - * Currently, the request is sent exactly as passed in by he user request. - * - * @param query hostname (not encoded) from the dns_table - * @param p pbuf containing the encoded hostname in the DNS response - * @param start_offset offset into p where the name starts - * @return 0xFFFF: names differ, other: names equal -> offset behind name - */ -static u16_t -dns_compare_name(const char *query, struct pbuf *p, u16_t start_offset) -{ - int n; - u16_t response_offset = start_offset; - - do { - n = pbuf_try_get_at(p, response_offset); - if ((n < 0) || (response_offset == 0xFFFF)) { - /* error or overflow */ - return 0xFFFF; - } - response_offset++; - /** @see RFC 1035 - 4.1.4. Message compression */ - if ((n & 0xc0) == 0xc0) { - /* Compressed name: cannot be equal since we don't send them */ - return 0xFFFF; - } else { - /* Not compressed name */ - while (n > 0) { - int c = pbuf_try_get_at(p, response_offset); - if (c < 0) { - return 0xFFFF; - } - if (lwip_tolower((*query)) != lwip_tolower((u8_t)c)) { - return 0xFFFF; - } - if (response_offset == 0xFFFF) { - /* would overflow */ - return 0xFFFF; - } - response_offset++; - ++query; - --n; - } - ++query; - } - n = pbuf_try_get_at(p, response_offset); - if (n < 0) { - return 0xFFFF; - } - } while (n != 0); - - if (response_offset == 0xFFFF) { - /* would overflow */ - return 0xFFFF; - } - return (u16_t)(response_offset + 1); -} - -/** - * Walk through a compact encoded DNS name and return the end of the name. - * - * @param p pbuf containing the name - * @param query_idx start index into p pointing to encoded DNS name in the DNS server response - * @return index to end of the name - */ -static u16_t -dns_skip_name(struct pbuf *p, u16_t query_idx) -{ - int n; - u16_t offset = query_idx; - - do { - n = pbuf_try_get_at(p, offset++); - if ((n < 0) || (offset == 0)) { - return 0xFFFF; - } - /** @see RFC 1035 - 4.1.4. Message compression */ - if ((n & 0xc0) == 0xc0) { - /* Compressed name: since we only want to skip it (not check it), stop here */ - break; - } else { - /* Not compressed name */ - if (offset + n >= p->tot_len) { - return 0xFFFF; - } - offset = (u16_t)(offset + n); - } - n = pbuf_try_get_at(p, offset); - if (n < 0) { - return 0xFFFF; - } - } while (n != 0); - - if (offset == 0xFFFF) { - return 0xFFFF; - } - return (u16_t)(offset + 1); -} - -/** - * Send a DNS query packet. - * - * @param idx the DNS table entry index for which to send a request - * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise - */ -static err_t -dns_send(u8_t idx) -{ - err_t err; - struct dns_hdr hdr; - struct dns_query qry; - struct pbuf *p; - u16_t query_idx, copy_len; - const char *hostname, *hostname_part; - u8_t n; - u8_t pcb_idx; - struct dns_table_entry *entry = &dns_table[idx]; - - LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", - (u16_t)(entry->server_idx), entry->name)); - LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS); - if (ip_addr_isany_val(dns_servers[entry->server_idx]) -#if LWIP_DNS_SUPPORT_MDNS_QUERIES - && !entry->is_mdns -#endif - ) { - /* DNS server not valid anymore, e.g. PPP netif has been shut down */ - /* call specified callback function if provided */ - dns_call_found(idx, NULL); - /* flush this entry */ - entry->state = DNS_STATE_UNUSED; - return ERR_OK; - } - - /* if here, we have either a new query or a retry on a previous query to process */ - p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 + - SIZEOF_DNS_QUERY), PBUF_RAM); - if (p != NULL) { - const ip_addr_t *dst; - u16_t dst_port; - /* fill dns header */ - memset(&hdr, 0, SIZEOF_DNS_HDR); - hdr.id = lwip_htons(entry->txid); - hdr.flags1 = DNS_FLAG1_RD; - hdr.numquestions = PP_HTONS(1); - pbuf_take(p, &hdr, SIZEOF_DNS_HDR); - hostname = entry->name; - --hostname; - - /* convert hostname into suitable query format. */ - query_idx = SIZEOF_DNS_HDR; - do { - ++hostname; - hostname_part = hostname; - for (n = 0; *hostname != '.' && *hostname != 0; ++hostname) { - ++n; - } - copy_len = (u16_t)(hostname - hostname_part); - if (query_idx + n + 1 > 0xFFFF) { - /* u16_t overflow */ - goto overflow_return; - } - pbuf_put_at(p, query_idx, n); - pbuf_take_at(p, hostname_part, copy_len, (u16_t)(query_idx + 1)); - query_idx = (u16_t)(query_idx + n + 1); - } while (*hostname != 0); - pbuf_put_at(p, query_idx, 0); - query_idx++; - - /* fill dns query */ - if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) { - qry.type = PP_HTONS(DNS_RRTYPE_AAAA); - } else { - qry.type = PP_HTONS(DNS_RRTYPE_A); - } - qry.cls = PP_HTONS(DNS_RRCLASS_IN); - pbuf_take_at(p, &qry, SIZEOF_DNS_QUERY, query_idx); - -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) - pcb_idx = entry->pcb_idx; -#else - pcb_idx = 0; -#endif - /* send dns packet */ - LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n", - entry->txid, entry->name, entry->server_idx)); -#if LWIP_DNS_SUPPORT_MDNS_QUERIES - if (entry->is_mdns) { - dst_port = DNS_MQUERY_PORT; -#if LWIP_IPV6 - if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) { - dst = &dns_mquery_v6group; - } -#endif -#if LWIP_IPV4 && LWIP_IPV6 - else -#endif -#if LWIP_IPV4 - { - dst = &dns_mquery_v4group; - } -#endif - } else -#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ - { - dst_port = DNS_SERVER_PORT; - dst = &dns_servers[entry->server_idx]; - } - err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port); - - /* free pbuf */ - pbuf_free(p); - } else { - err = ERR_MEM; - } - - return err; -overflow_return: - pbuf_free(p); - return ERR_VAL; -} - -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) -static struct udp_pcb * -dns_alloc_random_port(void) -{ - err_t err; - struct udp_pcb *pcb; - - pcb = udp_new_ip_type(IPADDR_TYPE_ANY); - if (pcb == NULL) { - /* out of memory, have to reuse an existing pcb */ - return NULL; - } - do { - u16_t port = (u16_t)DNS_RAND_TXID(); - if (DNS_PORT_ALLOWED(port)) { - err = udp_bind(pcb, IP_ANY_TYPE, port); - } else { - /* this port is not allowed, try again */ - err = ERR_USE; - } - } while (err == ERR_USE); - if (err != ERR_OK) { - udp_remove(pcb); - return NULL; - } - udp_recv(pcb, dns_recv, NULL); - return pcb; -} - -/** - * dns_alloc_pcb() - allocates a new pcb (or reuses an existing one) to be used - * for sending a request - * - * @return an index into dns_pcbs - */ -static u8_t -dns_alloc_pcb(void) -{ - u8_t i; - u8_t idx; - - for (i = 0; i < DNS_MAX_SOURCE_PORTS; i++) { - if (dns_pcbs[i] == NULL) { - break; - } - } - if (i < DNS_MAX_SOURCE_PORTS) { - dns_pcbs[i] = dns_alloc_random_port(); - if (dns_pcbs[i] != NULL) { - /* succeeded */ - dns_last_pcb_idx = i; - return i; - } - } - /* if we come here, creating a new UDP pcb failed, so we have to use - an already existing one (so overflow is no issue) */ - for (i = 0, idx = (u8_t)(dns_last_pcb_idx + 1); i < DNS_MAX_SOURCE_PORTS; i++, idx++) { - if (idx >= DNS_MAX_SOURCE_PORTS) { - idx = 0; - } - if (dns_pcbs[idx] != NULL) { - dns_last_pcb_idx = idx; - return idx; - } - } - return DNS_MAX_SOURCE_PORTS; -} -#endif /* ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) */ - -/** - * dns_call_found() - call the found callback and check if there are duplicate - * entries for the given hostname. If there are any, their found callback will - * be called and they will be removed. - * - * @param idx dns table index of the entry that is resolved or removed - * @param addr IP address for the hostname (or NULL on error or memory shortage) - */ -static void -dns_call_found(u8_t idx, ip_addr_t *addr) -{ -#if ((LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0) - u8_t i; -#endif - -#if LWIP_IPV4 && LWIP_IPV6 - if (addr != NULL) { - /* check that address type matches the request and adapt the table entry */ - if (IP_IS_V6_VAL(*addr)) { - LWIP_ASSERT("invalid response", LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype)); - dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6; - } else { - LWIP_ASSERT("invalid response", !LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype)); - dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4; - } - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) - for (i = 0; i < DNS_MAX_REQUESTS; i++) { - if (dns_requests[i].found && (dns_requests[i].dns_table_idx == idx)) { - (*dns_requests[i].found)(dns_table[idx].name, addr, dns_requests[i].arg); - /* flush this entry */ - dns_requests[i].found = NULL; - } - } -#else - if (dns_requests[idx].found) { - (*dns_requests[idx].found)(dns_table[idx].name, addr, dns_requests[idx].arg); - } - dns_requests[idx].found = NULL; -#endif -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) - /* close the pcb used unless other request are using it */ - for (i = 0; i < DNS_MAX_REQUESTS; i++) { - if (i == idx) { - continue; /* only check other requests */ - } - if (dns_table[i].state == DNS_STATE_ASKING) { - if (dns_table[i].pcb_idx == dns_table[idx].pcb_idx) { - /* another request is still using the same pcb */ - dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS; - break; - } - } - } - if (dns_table[idx].pcb_idx < DNS_MAX_SOURCE_PORTS) { - /* if we come here, the pcb is not used any more and can be removed */ - udp_remove(dns_pcbs[dns_table[idx].pcb_idx]); - dns_pcbs[dns_table[idx].pcb_idx] = NULL; - dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS; - } -#endif -} - -/* Create a query transmission ID that is unique for all outstanding queries */ -static u16_t -dns_create_txid(void) -{ - u16_t txid; - u8_t i; - -again: - txid = (u16_t)DNS_RAND_TXID(); - - /* check whether the ID is unique */ - for (i = 0; i < DNS_TABLE_SIZE; i++) { - if ((dns_table[i].state == DNS_STATE_ASKING) && - (dns_table[i].txid == txid)) { - /* ID already used by another pending query */ - goto again; - } - } - - return txid; -} - -/** - * Check whether there are other backup DNS servers available to try - */ -static u8_t -dns_backupserver_available(struct dns_table_entry *pentry) -{ - u8_t ret = 0; - - if (pentry) { - if ((pentry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[pentry->server_idx + 1])) { - ret = 1; - } - } - - return ret; -} - -/** - * dns_check_entry() - see if entry 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 -dns_check_entry(u8_t i) -{ - err_t err; - struct dns_table_entry *entry = &dns_table[i]; - - LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); - - switch (entry->state) { - case DNS_STATE_NEW: - /* initialize new entry */ - entry->txid = dns_create_txid(); - entry->state = DNS_STATE_ASKING; - entry->server_idx = 0; - entry->tmr = 1; - entry->retries = 0; - - /* send DNS packet for this entry */ - err = dns_send(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 (--entry->tmr == 0) { - if (++entry->retries == DNS_MAX_RETRIES) { - if (dns_backupserver_available(entry) -#if LWIP_DNS_SUPPORT_MDNS_QUERIES - && !entry->is_mdns -#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ - ) { - /* change of server */ - entry->server_idx++; - entry->tmr = 1; - entry->retries = 0; - } else { - LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", entry->name)); - /* call specified callback function if provided */ - dns_call_found(i, NULL); - /* flush this entry */ - entry->state = DNS_STATE_UNUSED; - break; - } - } else { - /* wait longer for the next retry */ - entry->tmr = entry->retries; - } - - /* send DNS packet for this entry */ - err = dns_send(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 ((entry->ttl == 0) || (--entry->ttl == 0)) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", entry->name)); - /* flush this entry, there cannot be any related pending entries in this state */ - entry->state = DNS_STATE_UNUSED; - } - 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 -dns_check_entries(void) -{ - u8_t i; - - for (i = 0; i < DNS_TABLE_SIZE; ++i) { - dns_check_entry(i); - } -} - -/** - * Save TTL and call dns_call_found for correct response. - */ -static void -dns_correct_response(u8_t idx, u32_t ttl) -{ - struct dns_table_entry *entry = &dns_table[idx]; - - entry->state = DNS_STATE_DONE; - - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", entry->name)); - ip_addr_debug_print_val(DNS_DEBUG, entry->ipaddr); - LWIP_DEBUGF(DNS_DEBUG, ("\n")); - - /* read the answer resource record's TTL, and maximize it if needed */ - entry->ttl = ttl; - if (entry->ttl > DNS_MAX_TTL) { - entry->ttl = DNS_MAX_TTL; - } - dns_call_found(idx, &entry->ipaddr); - - if (entry->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 */ - /* entry reused during callback? */ - if (entry->state == DNS_STATE_DONE) { - entry->state = DNS_STATE_UNUSED; - } - } -} - -/** - * Receive input function for DNS response packets arriving for the dns UDP pcb. - */ -static void -dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) -{ - u8_t i; - u16_t txid; - u16_t res_idx; - struct dns_hdr hdr; - struct dns_answer ans; - struct dns_query qry; - u16_t nquestions, nanswers; - - LWIP_UNUSED_ARG(arg); - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(port); - - /* is the dns message big enough ? */ - if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY)) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); - /* free pbuf and return */ - goto ignore_packet; - } - - /* copy dns payload inside static buffer for processing */ - if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, 0) == SIZEOF_DNS_HDR) { - /* Match the ID in the DNS header with the name table. */ - txid = lwip_htons(hdr.id); - for (i = 0; i < DNS_TABLE_SIZE; i++) { - struct dns_table_entry *entry = &dns_table[i]; - if ((entry->state == DNS_STATE_ASKING) && - (entry->txid == txid)) { - - /* We only care about the question(s) and the answers. The authrr - and the extrarr are simply discarded. */ - nquestions = lwip_htons(hdr.numquestions); - nanswers = lwip_htons(hdr.numanswers); - - /* Check for correct response. */ - if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": not a response\n", entry->name)); - goto ignore_packet; /* ignore this packet */ - } - if (nquestions != 1) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); - goto ignore_packet; /* ignore this packet */ - } - -#if LWIP_DNS_SUPPORT_MDNS_QUERIES - if (!entry->is_mdns) -#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ - { - /* Check whether response comes from the same network address to which the - question was sent. (RFC 5452) */ - if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) { - goto ignore_packet; /* ignore this packet */ - } - } - - /* Check if the name in the "question" part match with the name in the entry and - skip it if equal. */ - res_idx = dns_compare_name(entry->name, p, SIZEOF_DNS_HDR); - if (res_idx == 0xFFFF) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); - goto ignore_packet; /* ignore this packet */ - } - - /* check if "question" part matches the request */ - if (pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx) != SIZEOF_DNS_QUERY) { - goto ignore_packet; /* ignore this packet */ - } - if ((qry.cls != PP_HTONS(DNS_RRCLASS_IN)) || - (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_AAAA))) || - (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_A)))) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); - goto ignore_packet; /* ignore this packet */ - } - /* skip the rest of the "question" part */ - if (res_idx + SIZEOF_DNS_QUERY > 0xFFFF) { - goto ignore_packet; - } - res_idx = (u16_t)(res_idx + SIZEOF_DNS_QUERY); - - /* Check for error. If so, call callback to inform. */ - if (hdr.flags2 & DNS_FLAG2_ERR_MASK) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", entry->name)); - - /* if there is another backup DNS server to try - * then don't stop the DNS request - */ - if (dns_backupserver_available(entry)) { - /* avoid retrying the same server */ - entry->retries = DNS_MAX_RETRIES-1; - entry->tmr = 1; - - /* contact next available server for this entry */ - dns_check_entry(i); - - goto ignore_packet; - } - } else { - while ((nanswers > 0) && (res_idx < p->tot_len)) { - /* skip answer resource record's host name */ - res_idx = dns_skip_name(p, res_idx); - if (res_idx == 0xFFFF) { - goto ignore_packet; /* ignore this packet */ - } - - /* Check for IP address type and Internet class. Others are discarded. */ - if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) { - goto ignore_packet; /* ignore this packet */ - } - if (res_idx + SIZEOF_DNS_ANSWER > 0xFFFF) { - goto ignore_packet; - } - res_idx = (u16_t)(res_idx + SIZEOF_DNS_ANSWER); - - if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) { -#if LWIP_IPV4 - if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) { -#if LWIP_IPV4 && LWIP_IPV6 - if (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - { - ip4_addr_t ip4addr; - /* read the IP address after answer resource record's header */ - if (pbuf_copy_partial(p, &ip4addr, sizeof(ip4_addr_t), res_idx) != sizeof(ip4_addr_t)) { - goto ignore_packet; /* ignore this packet */ - } - ip_addr_copy_from_ip4(dns_table[i].ipaddr, ip4addr); - pbuf_free(p); - /* handle correct response */ - dns_correct_response(i, lwip_ntohl(ans.ttl)); - return; - } - } -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 - if ((ans.type == PP_HTONS(DNS_RRTYPE_AAAA)) && (ans.len == PP_HTONS(sizeof(ip6_addr_p_t)))) { -#if LWIP_IPV4 && LWIP_IPV6 - if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - { - ip6_addr_p_t ip6addr; - /* read the IP address after answer resource record's header */ - if (pbuf_copy_partial(p, &ip6addr, sizeof(ip6_addr_p_t), res_idx) != sizeof(ip6_addr_p_t)) { - goto ignore_packet; /* ignore this packet */ - } - /* @todo: scope ip6addr? Might be required for link-local addresses at least? */ - ip_addr_copy_from_ip6_packed(dns_table[i].ipaddr, ip6addr); - pbuf_free(p); - /* handle correct response */ - dns_correct_response(i, lwip_ntohl(ans.ttl)); - return; - } - } -#endif /* LWIP_IPV6 */ - } - /* skip this answer */ - if ((int)(res_idx + lwip_htons(ans.len)) > 0xFFFF) { - goto ignore_packet; /* ignore this packet */ - } - res_idx = (u16_t)(res_idx + lwip_htons(ans.len)); - --nanswers; - } -#if LWIP_IPV4 && LWIP_IPV6 - if ((entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || - (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { - if (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) { - /* IPv4 failed, try IPv6 */ - dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6; - } else { - /* IPv6 failed, try IPv4 */ - dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4; - } - pbuf_free(p); - dns_table[i].state = DNS_STATE_NEW; - dns_check_entry(i); - return; - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", entry->name)); - } - /* call callback to indicate error, clean up memory and return */ - pbuf_free(p); - dns_call_found(i, NULL); - dns_table[i].state = DNS_STATE_UNUSED; - return; - } - } - } - -ignore_packet: - /* deallocate memory and return */ - pbuf_free(p); - 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 hostnamelen length of the hostname - * @param found a callback function to be called on success, failure or timeout - * @param callback_arg argument to pass to the callback function - * @return err_t return code. - */ -static err_t -dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, - void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype) LWIP_DNS_ISMDNS_ARG(u8_t is_mdns)) -{ - u8_t i; - u8_t lseq, lseqi; - struct dns_table_entry *entry = NULL; - size_t namelen; - struct dns_req_entry *req; - -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) - u8_t r; - /* check for duplicate entries */ - for (i = 0; i < DNS_TABLE_SIZE; i++) { - if ((dns_table[i].state == DNS_STATE_ASKING) && - (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0)) { -#if LWIP_IPV4 && LWIP_IPV6 - if (dns_table[i].reqaddrtype != dns_addrtype) { - /* requested address types don't match - this can lead to 2 concurrent requests, but mixing the address types - for the same host should not be that common */ - continue; - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - /* this is a duplicate entry, find a free request entry */ - for (r = 0; r < DNS_MAX_REQUESTS; r++) { - if (dns_requests[r].found == 0) { - dns_requests[r].found = found; - dns_requests[r].arg = callback_arg; - dns_requests[r].dns_table_idx = i; - LWIP_DNS_SET_ADDRTYPE(dns_requests[r].reqaddrtype, dns_addrtype); - LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": duplicate request\n", name)); - return ERR_INPROGRESS; - } - } - } - } - /* no duplicate entries found */ -#endif - - /* search an unused entry, or the oldest one */ - lseq = 0; - lseqi = DNS_TABLE_SIZE; - for (i = 0; i < DNS_TABLE_SIZE; ++i) { - entry = &dns_table[i]; - /* is it an unused entry ? */ - if (entry->state == DNS_STATE_UNUSED) { - break; - } - /* check if this is the oldest completed entry */ - if (entry->state == DNS_STATE_DONE) { - u8_t age = (u8_t)(dns_seqno - entry->seqno); - if (age > lseq) { - lseq = age; - 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 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; - entry = &dns_table[i]; - } - } - -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) - /* find a free request entry */ - req = NULL; - for (r = 0; r < DNS_MAX_REQUESTS; r++) { - if (dns_requests[r].found == NULL) { - req = &dns_requests[r]; - break; - } - } - if (req == NULL) { - /* no request entry can be used now, table is full */ - LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS request entries table is full\n", name)); - return ERR_MEM; - } - req->dns_table_idx = i; -#else - /* in this configuration, the entry index is the same as the request index */ - req = &dns_requests[i]; -#endif - - /* use this entry */ - LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i))); - - /* fill the entry */ - entry->state = DNS_STATE_NEW; - entry->seqno = dns_seqno; - LWIP_DNS_SET_ADDRTYPE(entry->reqaddrtype, dns_addrtype); - LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype); - req->found = found; - req->arg = callback_arg; - namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH - 1); - MEMCPY(entry->name, name, namelen); - entry->name[namelen] = 0; - -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) - entry->pcb_idx = dns_alloc_pcb(); - if (entry->pcb_idx >= DNS_MAX_SOURCE_PORTS) { - /* failed to get a UDP pcb */ - LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": failed to allocate a pcb\n", name)); - entry->state = DNS_STATE_UNUSED; - req->found = NULL; - return ERR_MEM; - } - LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx))); -#endif - -#if LWIP_DNS_SUPPORT_MDNS_QUERIES - entry->is_mdns = is_mdns; -#endif - - dns_seqno++; - - /* force to send query without waiting timer */ - dns_check_entry(i); - - /* dns query is enqueued */ - return ERR_INPROGRESS; -} - -/** - * @ingroup dns - * 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 -dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, - void *callback_arg) -{ - return dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, LWIP_DNS_ADDRTYPE_DEFAULT); -} - -/** - * @ingroup dns - * Like dns_gethostbyname, but returned address type can be controlled: - * @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 - * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 first, try IPv6 if IPv4 fails only - * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 first, try IPv4 if IPv6 fails only - * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only - * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only - */ -err_t -dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, - void *callback_arg, u8_t dns_addrtype) -{ - size_t hostnamelen; -#if LWIP_DNS_SUPPORT_MDNS_QUERIES - u8_t is_mdns; -#endif - /* not initialized or no valid server yet, or invalid addr pointer - * or invalid hostname or invalid hostname length */ - if ((addr == NULL) || - (!hostname) || (!hostname[0])) { - return ERR_ARG; - } -#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0) - if (dns_pcbs[0] == NULL) { - return ERR_ARG; - } -#endif - hostnamelen = strlen(hostname); - if (hostnamelen >= DNS_MAX_NAME_LENGTH) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: name too long to resolve")); - return ERR_ARG; - } - - -#if LWIP_HAVE_LOOPIF - if (strcmp(hostname, "localhost") == 0) { - ip_addr_set_loopback(LWIP_DNS_ADDRTYPE_IS_IPV6(dns_addrtype), addr); - return ERR_OK; - } -#endif /* LWIP_HAVE_LOOPIF */ - - /* host name already in octet notation? set ip addr and return ERR_OK */ - if (ipaddr_aton(hostname, addr)) { -#if LWIP_IPV4 && LWIP_IPV6 - if ((IP_IS_V6(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV4)) || - (IP_IS_V4(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV6))) -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - { - return ERR_OK; - } - } - /* already have this address cached? */ - if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { - return ERR_OK; - } -#if LWIP_IPV4 && LWIP_IPV6 - if ((dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { - /* fallback to 2nd IP type and try again to lookup */ - u8_t fallback; - if (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) { - fallback = LWIP_DNS_ADDRTYPE_IPV6; - } else { - fallback = LWIP_DNS_ADDRTYPE_IPV4; - } - if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) { - return ERR_OK; - } - } -#else /* LWIP_IPV4 && LWIP_IPV6 */ - LWIP_UNUSED_ARG(dns_addrtype); -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - -#if LWIP_DNS_SUPPORT_MDNS_QUERIES - if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) { - is_mdns = 1; - } else { - is_mdns = 0; - } - - if (!is_mdns) -#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ - { - /* prevent calling found callback if no server is set, return error instead */ - if (ip_addr_isany_val(dns_servers[0])) { - return ERR_VAL; - } - } - - /* queue query with specified callback */ - return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype) - LWIP_DNS_ISMDNS_ARG(is_mdns)); -} - -#endif /* LWIP_DNS */ diff --git a/core/c/core/inet_chksum.c b/core/c/core/inet_chksum.c deleted file mode 100755 index 25255b9..0000000 --- a/core/c/core/inet_chksum.c +++ /dev/null @@ -1,608 +0,0 @@ -/** - * @file - * Internet checksum functions.\n - * - * These are some reference implementations of the checksum algorithm, with the - * aim of being simple, correct and fully portable. Checksumming is the - * first thing you would want to optimize for your platform. If you create - * your own version, link it in and in your cc.h put: - * - * \#define LWIP_CHKSUM your_checksum_routine - * - * Or you can select from the implementations below by defining - * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3. - */ - -/* - * 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 "lwip/ip_addr.h" - -#include - -#ifndef LWIP_CHKSUM -# define LWIP_CHKSUM lwip_standard_chksum -# ifndef LWIP_CHKSUM_ALGORITHM -# define LWIP_CHKSUM_ALGORITHM 2 -# endif -u16_t lwip_standard_chksum(const void *dataptr, int len); -#endif -/* If none set: */ -#ifndef LWIP_CHKSUM_ALGORITHM -# 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) - */ -u16_t -lwip_standard_chksum(const void *dataptr, int len) -{ - u32_t acc; - u16_t src; - const u8_t *octetptr; - - acc = 0; - /* dataptr may be at odd or even addresses */ - octetptr = (const 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 lwip_htons() - instead of lwip_ntohs() since it has a little less call overhead. - The caller must invert bits for Internet sum ! */ - return lwip_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) - */ -u16_t -lwip_standard_chksum(const void *dataptr, int len) -{ - const u8_t *pb = (const u8_t *)dataptr; - const u16_t *ps; - u16_t 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 = (const u16_t *)(const void *)pb; - while (len > 1) { - sum += *ps++; - len -= 2; - } - - /* Consume left-over byte, if any */ - if (len > 0) { - ((u8_t *)&t)[0] = *(const u8_t *)ps; - } - - /* Add end bytes */ - sum += t; - - /* Fold 32-bit sum to 16 bits - calling this twice is probably 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 - */ -u16_t -lwip_standard_chksum(const void *dataptr, int len) -{ - const u8_t *pb = (const u8_t *)dataptr; - const u16_t *ps; - u16_t t = 0; - const 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 = (const u16_t *)(const void *)pb; - - if (((mem_ptr_t)ps & 3) && len > 1) { - sum += *ps++; - len -= 2; - } - - pl = (const u32_t *)(const void *)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 = (const 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] = *(const u8_t *)ps; - } - - sum += t; /* add end bytes */ - - /* Fold 32-bit sum to 16 bits - calling this twice is probably 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 - -/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ -static u16_t -inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc) -{ - struct pbuf *q; - int 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 = !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); - } - - acc += (u32_t)lwip_htons((u16_t)proto); - acc += (u32_t)lwip_htons(proto_len); - - /* Fold 32-bit sum to 16 bits - calling this twice is probably faster than if statements... */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); - return (u16_t)~(acc & 0xffffUL); -} - -#if LWIP_IPV4 -/* inet_chksum_pseudo: - * - * Calculates the IPv4 pseudo Internet checksum used by TCP and UDP for a pbuf chain. - * IP addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ip address (used for checksum of pseudo header) - * @param dst destination ip address (used for checksum of pseudo header) - * @param proto ip protocol (used for checksum of pseudo header) - * @param proto_len length of the ip data part (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, - const ip4_addr_t *src, const ip4_addr_t *dest) -{ - u32_t acc; - u32_t addr; - - addr = ip4_addr_get_u32(src); - acc = (addr & 0xffffUL); - acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); - addr = ip4_addr_get_u32(dest); - acc = (u32_t)(acc + (addr & 0xffffUL)); - acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); - /* fold down to 16 bits */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - - return inet_cksum_pseudo_base(p, proto, proto_len, acc); -} -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6 -/** - * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. - * IPv6 addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param proto ipv6 protocol/next header (used for checksum of pseudo header) - * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) - * @param src source ipv6 address (used for checksum of pseudo header) - * @param dest destination ipv6 address (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, - const ip6_addr_t *src, const ip6_addr_t *dest) -{ - u32_t acc = 0; - u32_t addr; - u8_t addr_part; - - for (addr_part = 0; addr_part < 4; addr_part++) { - addr = src->addr[addr_part]; - acc = (u32_t)(acc + (addr & 0xffffUL)); - acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); - addr = dest->addr[addr_part]; - acc = (u32_t)(acc + (addr & 0xffffUL)); - acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); - } - /* fold down to 16 bits */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - - return inet_cksum_pseudo_base(p, proto, proto_len, acc); -} -#endif /* LWIP_IPV6 */ - -/* ip_chksum_pseudo: - * - * Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain. - * IP addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ip address (used for checksum of pseudo header) - * @param dst destination ip address (used for checksum of pseudo header) - * @param proto ip protocol (used for checksum of pseudo header) - * @param proto_len length of the ip data part (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, - const ip_addr_t *src, const ip_addr_t *dest) -{ -#if LWIP_IPV6 - if (IP_IS_V6(dest)) { - return ip6_chksum_pseudo(p, proto, proto_len, ip_2_ip6(src), ip_2_ip6(dest)); - } -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 && LWIP_IPV6 - else -#endif /* LWIP_IPV4 && LWIP_IPV6 */ -#if LWIP_IPV4 - { - return inet_chksum_pseudo(p, proto, proto_len, ip_2_ip4(src), ip_2_ip4(dest)); - } -#endif /* LWIP_IPV4 */ -} - -/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ -static u16_t -inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len, - u16_t chksum_len, u32_t acc) -{ - struct pbuf *q; - int swapped = 0; - u16_t chklen; - - /* 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 = (u16_t)(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 = !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); - } - - acc += (u32_t)lwip_htons((u16_t)proto); - acc += (u32_t)lwip_htons(proto_len); - - /* Fold 32-bit sum to 16 bits - calling this twice is probably faster than if statements... */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); - return (u16_t)~(acc & 0xffffUL); -} - -#if LWIP_IPV4 -/* inet_chksum_pseudo_partial: - * - * Calculates the IPv4 pseudo Internet checksum used by TCP and UDP for a pbuf chain. - * IP addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ip address (used for checksum of pseudo header) - * @param dst destination ip address (used for checksum of pseudo header) - * @param proto ip protocol (used for checksum of pseudo header) - * @param proto_len length of the ip data part (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, - u16_t chksum_len, const ip4_addr_t *src, const ip4_addr_t *dest) -{ - u32_t acc; - u32_t addr; - - addr = ip4_addr_get_u32(src); - acc = (addr & 0xffffUL); - acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); - addr = ip4_addr_get_u32(dest); - acc = (u32_t)(acc + (addr & 0xffffUL)); - acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); - /* fold down to 16 bits */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - - return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); -} -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6 -/** - * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. - * IPv6 addresses are expected to be in network byte order. Will only compute for a - * portion of the payload. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param proto ipv6 protocol/next header (used for checksum of pseudo header) - * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) - * @param chksum_len number of payload bytes used to compute chksum - * @param src source ipv6 address (used for checksum of pseudo header) - * @param dest destination ipv6 address (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, - u16_t chksum_len, const ip6_addr_t *src, const ip6_addr_t *dest) -{ - u32_t acc = 0; - u32_t addr; - u8_t addr_part; - - for (addr_part = 0; addr_part < 4; addr_part++) { - addr = src->addr[addr_part]; - acc = (u32_t)(acc + (addr & 0xffffUL)); - acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); - addr = dest->addr[addr_part]; - acc = (u32_t)(acc + (addr & 0xffffUL)); - acc = (u32_t)(acc + ((addr >> 16) & 0xffffUL)); - } - /* fold down to 16 bits */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - - return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); -} -#endif /* LWIP_IPV6 */ - -/* ip_chksum_pseudo_partial: - * - * Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ip address (used for checksum of pseudo header) - * @param dst destination ip address (used for checksum of pseudo header) - * @param proto ip protocol (used for checksum of pseudo header) - * @param proto_len length of the ip data part (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, - u16_t chksum_len, const ip_addr_t *src, const ip_addr_t *dest) -{ -#if LWIP_IPV6 - if (IP_IS_V6(dest)) { - return ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip6(src), ip_2_ip6(dest)); - } -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 && LWIP_IPV6 - else -#endif /* LWIP_IPV4 && LWIP_IPV6 */ -#if LWIP_IPV4 - { - return inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip4(src), ip_2_ip4(dest)); - } -#endif /* LWIP_IPV4 */ -} - -/* 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(const void *dataptr, u16_t len) -{ - return (u16_t)~(unsigned int)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; - int swapped = 0; - - acc = 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 = !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/core/c/core/init.c b/core/c/core/init.c deleted file mode 100755 index b688536..0000000 --- a/core/c/core/init.c +++ /dev/null @@ -1,380 +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/priv/tcp_priv.h" -#include "lwip/igmp.h" -#include "lwip/dns.h" -#include "lwip/timeouts.h" -#include "lwip/etharp.h" -#include "lwip/ip6.h" -#include "lwip/nd6.h" -#include "lwip/mld6.h" -#include "lwip/api.h" - -#include "netif/ppp/ppp_opts.h" -#include "netif/ppp/ppp_impl.h" - -#ifndef LWIP_SKIP_PACKING_CHECK - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct packed_struct_test { - PACK_STRUCT_FLD_8(u8_t dummy1); - PACK_STRUCT_FIELD(u32_t dummy2); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -#define PACKED_STRUCT_TEST_EXPECTED_SIZE 5 - -#endif - -/* Compile-time sanity checks for configuration errors. - * These can be done independently of LWIP_DEBUG, without penalty. - */ -#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_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_DHCP) -#error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h" -#endif -#if (!LWIP_UDP && !LWIP_RAW && LWIP_MULTICAST_TX_OPTIONS) -#error "If you want to use LWIP_MULTICAST_TX_OPTIONS, you have to define LWIP_UDP=1 and/or LWIP_RAW=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 !MEMP_MEM_MALLOC /* MEMP_NUM_* checks are disabled when not using the pool allocator */ -#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_IGMP && (MEMP_NUM_IGMP_GROUP<=1)) -#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h" -#endif -#if (LWIP_IGMP && !LWIP_MULTICAST_TX_OPTIONS) -#error "If you want to use IGMP, you have to define LWIP_MULTICAST_TX_OPTIONS==1 in your lwipopts.h" -#endif -#if (LWIP_IGMP && !LWIP_IPV4) -#error "IGMP needs LWIP_IPV4 enabled in your lwipopts.h" -#endif -#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0)) -#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h" -#endif -/* There must be sufficient timeouts, taking into account requirements of the subsystems. */ -#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < LWIP_NUM_SYS_TIMEOUT_INTERNAL) -#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts" -#endif -#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS)) -#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!" -#endif -#endif /* !MEMP_MEM_MALLOC */ -#if LWIP_WND_SCALE -#if (LWIP_TCP && (TCP_WND > 0xffffffff)) -#error "If you want to use TCP, TCP_WND must fit in an u32_t, so, you have to reduce it in your lwipopts.h" -#endif -#if (LWIP_TCP && (TCP_RCV_SCALE > 14)) -#error "The maximum valid window scale value is 14!" -#endif -#if (LWIP_TCP && (TCP_WND > (0xFFFFU << TCP_RCV_SCALE))) -#error "TCP_WND is bigger than the configured LWIP_WND_SCALE allows!" -#endif -#if (LWIP_TCP && ((TCP_WND >> TCP_RCV_SCALE) == 0)) -#error "TCP_WND is too small for the configured LWIP_WND_SCALE (results in zero window)!" -#endif -#else /* LWIP_WND_SCALE */ -#if (LWIP_TCP && (TCP_WND > 0xffff)) -#error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h (or enable window scaling)" -#endif -#endif /* LWIP_WND_SCALE */ -#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff)) -#error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h" -#endif -#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_TCP && LWIP_TCP_SACK_OUT && !TCP_QUEUE_OOSEQ) -#error "To use LWIP_TCP_SACK_OUT, TCP_QUEUE_OOSEQ needs to be enabled" -#endif -#if (LWIP_TCP && LWIP_TCP_SACK_OUT && (LWIP_TCP_MAX_SACK_NUM < 1)) -#error "LWIP_TCP_MAX_SACK_NUM must be greater than 0" -#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_PPP_API && (NO_SYS==1)) -#error "If you want to use PPP API, you have to define NO_SYS=0 in your lwipopts.h" -#endif -#if (LWIP_PPP_API && (PPP_SUPPORT==0)) -#error "If you want to use PPP API, you have to enable PPP_SUPPORT in your lwipopts.h" -#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_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 -#if (LWIP_ALTCP && LWIP_EVENT_API) -#error "The application layered tcp API does not work with LWIP_EVENT_API" -#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 (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT))) -#error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST" -#endif -#if PPP_SUPPORT && !PPPOS_SUPPORT && !PPPOE_SUPPORT && !PPPOL2TP_SUPPORT -#error "PPP_SUPPORT needs at least one of PPPOS_SUPPORT, PPPOE_SUPPORT or PPPOL2TP_SUPPORT turned on" -#endif -#if PPP_SUPPORT && !PPP_IPV4_SUPPORT && !PPP_IPV6_SUPPORT -#error "PPP_SUPPORT needs PPP_IPV4_SUPPORT and/or PPP_IPV6_SUPPORT turned on" -#endif -#if PPP_SUPPORT && PPP_IPV4_SUPPORT && !LWIP_IPV4 -#error "PPP_IPV4_SUPPORT needs LWIP_IPV4 turned on" -#endif -#if PPP_SUPPORT && PPP_IPV6_SUPPORT && !LWIP_IPV6 -#error "PPP_IPV6_SUPPORT needs LWIP_IPV6 turned on" -#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_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 LWIP_NETCONN && LWIP_TCP -#if NETCONN_COPY != TCP_WRITE_FLAG_COPY -#error "NETCONN_COPY != TCP_WRITE_FLAG_COPY" -#endif -#if NETCONN_MORE != TCP_WRITE_FLAG_MORE -#error "NETCONN_MORE != TCP_WRITE_FLAG_MORE" -#endif -#endif /* LWIP_NETCONN && LWIP_TCP */ -#if LWIP_SOCKET -#endif /* LWIP_SOCKET */ - - -/* 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 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 -#if !NO_SYS && LWIP_TCPIP_CORE_LOCKING && LWIP_COMPAT_MUTEX && !defined(LWIP_COMPAT_MUTEX_ALLOWED) -#error "LWIP_COMPAT_MUTEX cannot prevent priority inversion. It is recommended to implement priority-aware mutexes. (Define LWIP_COMPAT_MUTEX_ALLOWED to disable this error.)" -#endif - -#ifndef LWIP_DISABLE_TCP_SANITY_CHECKS -#define LWIP_DISABLE_TCP_SANITY_CHECKS 0 -#endif -#ifndef LWIP_DISABLE_MEMP_SANITY_CHECKS -#define LWIP_DISABLE_MEMP_SANITY_CHECKS 0 -#endif - -/* MEMP sanity checks */ -#if MEMP_MEM_MALLOC -#if !LWIP_DISABLE_MEMP_SANITY_CHECKS -#if LWIP_NETCONN || LWIP_SOCKET -#if !MEMP_NUM_NETCONN && LWIP_SOCKET -#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN cannot be 0 when using sockets!" -#endif -#else /* MEMP_MEM_MALLOC */ -#if MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB) -#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN. If you know what you are doing, define LWIP_DISABLE_MEMP_SANITY_CHECKS to 1 to disable this error." -#endif -#endif /* LWIP_NETCONN || LWIP_SOCKET */ -#endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */ -#if MEM_USE_POOLS -#error "MEMP_MEM_MALLOC and MEM_USE_POOLS cannot be enabled at the same time" -#endif -#ifdef LWIP_HOOK_MEMP_AVAILABLE -#error "LWIP_HOOK_MEMP_AVAILABLE doesn't make sense with MEMP_MEM_MALLOC" -#endif -#endif /* MEMP_MEM_MALLOC */ - -/* TCP sanity checks */ -#if !LWIP_DISABLE_TCP_SANITY_CHECKS -#if LWIP_TCP -#if !MEMP_MEM_MALLOC && (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN) -#error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if TCP_SND_BUF < (2 * TCP_MSS) -#error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF / TCP_MSS)) -#error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if TCP_SNDLOWAT >= TCP_SND_BUF -#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if TCP_SNDLOWAT >= (0xFFFF - (4 * TCP_MSS)) -#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must at least be 4*MSS below u16_t overflow!" -#endif -#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN -#error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (PBUF_POOL_BUFSIZE <= (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) -#error "lwip_sanity_check: WARNING: PBUF_POOL_BUFSIZE does not provide enough space for protocol headers. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)))) -#error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if TCP_WND < TCP_MSS -#error "lwip_sanity_check: WARNING: TCP_WND is smaller than MSS. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#endif /* LWIP_TCP */ -#endif /* !LWIP_DISABLE_TCP_SANITY_CHECKS */ - -/** - * @ingroup lwip_nosys - * Initialize all modules. - * Use this in NO_SYS mode. Use tcpip_init() otherwise. - */ -void -lwip_init(void) -{ -#ifndef LWIP_SKIP_CONST_CHECK - int a = 0; - LWIP_UNUSED_ARG(a); - LWIP_ASSERT("LWIP_CONST_CAST not implemented correctly. Check your lwIP port.", LWIP_CONST_CAST(void *, &a) == &a); -#endif -#ifndef LWIP_SKIP_PACKING_CHECK - LWIP_ASSERT("Struct packing not implemented correctly. Check your lwIP port.", sizeof(struct packed_struct_test) == PACKED_STRUCT_TEST_EXPECTED_SIZE); -#endif - - /* Modules initialization */ - stats_init(); -#if !NO_SYS - sys_init(); -#endif /* !NO_SYS */ - mem_init(); - memp_init(); - pbuf_init(); - netif_init(); -#if LWIP_IPV4 - ip_init(); -#if LWIP_ARP - etharp_init(); -#endif /* LWIP_ARP */ -#endif /* LWIP_IPV4 */ -#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_IGMP - igmp_init(); -#endif /* LWIP_IGMP */ -#if LWIP_DNS - dns_init(); -#endif /* LWIP_DNS */ -#if PPP_SUPPORT - ppp_init(); -#endif - -#if LWIP_TIMERS - sys_timeouts_init(); -#endif /* LWIP_TIMERS */ -} diff --git a/core/c/core/ip.c b/core/c/core/ip.c deleted file mode 100755 index d611315..0000000 --- a/core/c/core/ip.c +++ /dev/null @@ -1,167 +0,0 @@ -/** - * @file - * Common IPv4 and IPv6 code - * - * @defgroup ip IP - * @ingroup callbackstyle_api - * - * @defgroup ip4 IPv4 - * @ingroup ip - * - * @defgroup ip6 IPv6 - * @ingroup ip - * - * @defgroup ipaddr IP address handling - * @ingroup infrastructure - * - * @defgroup ip4addr IPv4 only - * @ingroup ipaddr - * - * @defgroup ip6addr IPv6 only - * @ingroup ipaddr - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#include "lwip/opt.h" - -#if LWIP_IPV4 || LWIP_IPV6 - -#include "lwip/ip_addr.h" -#include "lwip/ip.h" - -/** Global data for both IPv4 and IPv6 */ -struct ip_globals ip_data; - -#if LWIP_IPV4 && LWIP_IPV6 - -const ip_addr_t ip_addr_any_type = IPADDR_ANY_TYPE_INIT; - -/** - * @ingroup ipaddr - * Convert numeric IP address (both versions) into 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 - * representation of addr - */ -char *ipaddr_ntoa(const ip_addr_t *addr) -{ - if (addr == NULL) { - return NULL; - } - if (IP_IS_V6(addr)) { - return ip6addr_ntoa(ip_2_ip6(addr)); - } else { - return ip4addr_ntoa(ip_2_ip4(addr)); - } -} - -/** - * @ingroup ipaddr - * 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) -{ - if (addr == NULL) { - return NULL; - } - if (IP_IS_V6(addr)) { - return ip6addr_ntoa_r(ip_2_ip6(addr), buf, buflen); - } else { - return ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen); - } -} - -/** - * @ingroup ipaddr - * Convert IP address string (both versions) to numeric. - * The version is auto-detected from the string. - * - * @param cp IP address string to convert - * @param addr conversion result is stored here - * @return 1 on success, 0 on error - */ -int -ipaddr_aton(const char *cp, ip_addr_t *addr) -{ - if (cp != NULL) { - const char *c; - for (c = cp; *c != 0; c++) { - if (*c == ':') { - /* contains a colon: IPv6 address */ - if (addr) { - IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V6); - } - return ip6addr_aton(cp, ip_2_ip6(addr)); - } else if (*c == '.') { - /* contains a dot: IPv4 address */ - break; - } - } - /* call ip4addr_aton as fallback or if IPv4 was found */ - if (addr) { - IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V4); - } - return ip4addr_aton(cp, ip_2_ip4(addr)); - } - return 0; -} - -/** - * @ingroup lwip_nosys - * If both IP versions are enabled, this function can dispatch packets to the correct one. - * Don't call directly, pass to netif_add() and call netif->input(). - */ -err_t -ip_input(struct pbuf *p, struct netif *inp) -{ - if (p != NULL) { - if (IP_HDR_GET_VERSION(p->payload) == 6) { - return ip6_input(p, inp); - } - return ip4_input(p, inp); - } - return ERR_VAL; -} - -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - -#endif /* LWIP_IPV4 || LWIP_IPV6 */ diff --git a/core/c/core/ipv4/autoip.c b/core/c/core/ipv4/autoip.c deleted file mode 100755 index a454504..0000000 --- a/core/c/core/ipv4/autoip.c +++ /dev/null @@ -1,527 +0,0 @@ -/** - * @file - * AutoIP Automatic LinkLocal IP Configuration - * - * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform - * with RFC 3927. - * - * @defgroup autoip AUTOIP - * @ingroup ip4 - * AUTOIP related functions - * USAGE: - * - * define @ref LWIP_AUTOIP 1 in your lwipopts.h - * Options: - * AUTOIP_TMR_INTERVAL msecs, - * I recommend a value of 100. The value must divide 1000 with a remainder almost 0. - * Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 .... - * - * Without DHCP: - * - Call autoip_start() after netif_add(). - * - * With DHCP: - * - define @ref LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h. - * - Configure your DHCP Client. - * - * @see netifapi_autoip - */ - -/* - * - * 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 - */ - -#include "lwip/opt.h" - -#if LWIP_IPV4 && 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 "lwip/etharp.h" -#include "lwip/prot/autoip.h" - -#include - -/** 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_data(netif)? netif_autoip_data(netif)->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) \ - lwip_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 err_t autoip_arp_announce(struct netif *netif); -static void autoip_start_probing(struct netif *netif); - -/** - * @ingroup autoip - * Set a statically allocated struct autoip to work with. - * Using this prevents autoip_start to allocate it using mem_malloc. - * - * @param netif the netif for which to set the struct autoip - * @param autoip (uninitialised) autoip struct allocated by the application - */ -void -autoip_set_struct(struct netif *netif, struct autoip *autoip) -{ - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ASSERT("netif != NULL", netif != NULL); - LWIP_ASSERT("autoip != NULL", autoip != NULL); - LWIP_ASSERT("netif already has a struct autoip set", - netif_autoip_data(netif) == NULL); - - /* clear data structure */ - memset(autoip, 0, sizeof(struct autoip)); - /* autoip->state = AUTOIP_STATE_OFF; */ - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip); -} - -/** Restart AutoIP client and check the next address (conflict detected) - * - * @param netif The netif under AutoIP control - */ -static void -autoip_restart(struct netif *netif) -{ - struct autoip *autoip = netif_autoip_data(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) -{ - struct autoip *autoip = netif_autoip_data(netif); - - /* RFC3927, 2.5 "Conflict Detection and Defense" allows two options where - a) means retreat on the first conflict and - b) allows to keep an already configured address when having only one - conflict in 10 seconds - We use option b) since it helps to improve the chance that one of the two - conflicting hosts may be able to retain its address. */ - - if (autoip->lastconflict > 0) { - /* retreat, there was a conflicting ARP in the last DEFEND_INTERVAL seconds */ - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); - - /* Active TCP sessions are aborted when removing the ip addresss */ - autoip_restart(netif); - } else { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); - autoip_arp_announce(netif); - autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND; - } -} - -/** - * 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, ip4_addr_t *ipaddr) -{ - struct autoip *autoip = netif_autoip_data(netif); - - /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 - * compliant to RFC 3927 Section 2.1 - * We have 254 * 256 possibilities */ - - u32_t addr = lwip_ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); - addr += autoip->tried_llipaddr; - 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, lwip_htonl(addr)); - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - (u16_t)(autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), - 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) -{ - struct autoip *autoip = netif_autoip_data(netif); - /* this works because netif->ip_addr is ANY */ - return etharp_request(netif, &autoip->llipaddr); -} - -/** - * 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_gratuitous(netif); -} - -/** - * 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_data(netif); - ip4_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_addr(netif, &autoip->llipaddr, &sn_mask, &gw_addr); - /* interface is used by routing now that an address is set */ - - return ERR_OK; -} - -/** - * @ingroup autoip - * 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_data(netif); - err_t result = ERR_OK; - - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;); - - /* Set IP-Address, Netmask and Gateway to 0 to make sure that - * ARP Packets are formed correctly - */ - netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); - - 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_calloc(1, sizeof(struct autoip)); - if (autoip == NULL) { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_start(): could not allocate autoip\n")); - return ERR_MEM; - } - /* store this AutoIP client in the netif */ - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip); - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); - } else { - autoip->state = AUTOIP_STATE_OFF; - autoip->ttw = 0; - autoip->sent_num = 0; - ip4_addr_set_zero(&autoip->llipaddr); - 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_data(netif); - - autoip->state = AUTOIP_STATE_PROBING; - autoip->sent_num = 0; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), - ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); - - /* time to wait to first probe, this is randomly - * chosen out of 0 to PROBE_WAIT seconds. - * compliant to RFC 3927 Section 2.2.1 - */ - autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND)); - - /* - * if we tried more then MAX_CONFLICTS we must limit our rate for - * acquiring and probing address - * 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) -{ - struct autoip *autoip = netif_autoip_data(netif); - - if (autoip && (autoip->state != AUTOIP_STATE_OFF)) { - autoip_start_probing(netif); - } -} - -/** - * @ingroup autoip - * Stop AutoIP client - * - * @param netif network interface on which stop the AutoIP client - */ -err_t -autoip_stop(struct netif *netif) -{ - struct autoip *autoip = netif_autoip_data(netif); - - LWIP_ASSERT_CORE_LOCKED(); - if (autoip != NULL) { - autoip->state = AUTOIP_STATE_OFF; - if (ip4_addr_islinklocal(netif_ip4_addr(netif))) { - netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); - } - } - return ERR_OK; -} - -/** - * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds - */ -void -autoip_tmr(void) -{ - struct netif *netif; - /* loop through netif's */ - NETIF_FOREACH(netif) { - struct autoip *autoip = netif_autoip_data(netif); - /* only act on AutoIP configured interfaces */ - if (autoip != NULL) { - if (autoip->lastconflict > 0) { - autoip->lastconflict--; - } - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n", - (u16_t)(autoip->state), autoip->ttw)); - - if (autoip->ttw > 0) { - autoip->ttw--; - } - - switch (autoip->state) { - case AUTOIP_STATE_PROBING: - if (autoip->ttw == 0) { - if (autoip->sent_num >= PROBE_NUM) { - /* Switch to ANNOUNCING: now we can bind to an IP address and use it */ - autoip->state = AUTOIP_STATE_ANNOUNCING; - autoip_bind(netif); - /* autoip_bind() calls netif_set_addr(): this triggers a gratuitous ARP - which counts as an announcement */ - autoip->sent_num = 1; - autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), - ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); - } else { - autoip_arp_probe(netif); - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() PROBING Sent Probe\n")); - autoip->sent_num++; - if (autoip->sent_num == PROBE_NUM) { - /* calculate time to wait to for announce */ - autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; - } else { - /* calculate time to wait to next probe */ - autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) % - ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) + - PROBE_MIN * AUTOIP_TICKS_PER_SECOND); - } - } - } - break; - - case AUTOIP_STATE_ANNOUNCING: - if (autoip->ttw == 0) { - autoip_arp_announce(netif); - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() ANNOUNCING Sent Announce\n")); - autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; - autoip->sent_num++; - - if (autoip->sent_num >= ANNOUNCE_NUM) { - autoip->state = AUTOIP_STATE_BOUND; - autoip->sent_num = 0; - autoip->ttw = 0; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), - ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); - } - } - break; - - default: - /* nothing to do in other states */ - break; - } - } - } -} - -/** - * Handles every incoming ARP Packet, called by etharp_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) -{ - struct autoip *autoip = netif_autoip_data(netif); - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n")); - if ((autoip != NULL) && (autoip->state != AUTOIP_STATE_OFF)) { - /* when ip.src == llipaddr && hw.src != netif->hwaddr - * - * when probing ip.dst == llipaddr && hw.src != netif->hwaddr - * we have a conflict and must solve it - */ - ip4_addr_t sipaddr, dipaddr; - struct eth_addr netifaddr; - SMEMCPY(netifaddr.addr, netif->hwaddr, ETH_HWADDR_LEN); - - /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support compilers without - * structure packing (not using structure copy which breaks strict-aliasing rules). - */ - IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr); - IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr); - - if (autoip->state == AUTOIP_STATE_PROBING) { - /* RFC 3927 Section 2.2.1: - * from beginning to after ANNOUNCE_WAIT - * seconds we have a conflict if - * ip.src == llipaddr OR - * ip.dst == llipaddr && hw.src != own hwaddr - */ - if ((ip4_addr_cmp(&sipaddr, &autoip->llipaddr)) || - (ip4_addr_isany_val(sipaddr) && - ip4_addr_cmp(&dipaddr, &autoip->llipaddr) && - !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 (ip4_addr_cmp(&sipaddr, &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); - } - } - } -} - -/** check if AutoIP supplied netif->ip_addr - * - * @param netif the netif to check - * @return 1 if AutoIP supplied netif->ip_addr (state BOUND or ANNOUNCING), - * 0 otherwise - */ -u8_t -autoip_supplied_address(const struct netif *netif) -{ - if ((netif != NULL) && (netif_autoip_data(netif) != NULL)) { - struct autoip *autoip = netif_autoip_data(netif); - return (autoip->state == AUTOIP_STATE_BOUND) || (autoip->state == AUTOIP_STATE_ANNOUNCING); - } - return 0; -} - -u8_t -autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr) -{ - struct autoip *autoip = netif_autoip_data(netif); - return (autoip != NULL) && ip4_addr_cmp(addr, &(autoip->llipaddr)); -} - -#endif /* LWIP_IPV4 && LWIP_AUTOIP */ diff --git a/core/c/core/ipv4/dhcp.c b/core/c/core/ipv4/dhcp.c deleted file mode 100755 index 89f9c41..0000000 --- a/core/c/core/ipv4/dhcp.c +++ /dev/null @@ -1,1990 +0,0 @@ -/** - * @file - * Dynamic Host Configuration Protocol client - * - * @defgroup dhcp4 DHCPv4 - * @ingroup ip4 - * DHCP (IPv4) related functions - * 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, ...) - * - * Options: - * @ref DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute) - * @ref DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer) - * - * dhcp_start() starts a DHCP client instance which - * configures the interface by obtaining an IP address lease and maintaining it. - * - * Use dhcp_release() to end the lease and use dhcp_stop() - * to remove the DHCP client. - * - * @see LWIP_HOOK_DHCP_APPEND_OPTIONS - * @see LWIP_HOOK_DHCP_PARSE_OPTION - * - * @see netifapi_dhcp4 - */ - -/* - * 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 part of 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 - * - */ - -#include "lwip/opt.h" - -#if LWIP_IPV4 && 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/dhcp.h" -#include "lwip/autoip.h" -#include "lwip/dns.h" -#include "lwip/etharp.h" -#include "lwip/prot/dhcp.h" -#include "lwip/prot/iana.h" - -#include - -#ifdef LWIP_HOOK_FILENAME -#include LWIP_HOOK_FILENAME -#endif -#ifndef LWIP_HOOK_DHCP_APPEND_OPTIONS -#define LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, state, msg, msg_type, options_len_ptr) -#endif -#ifndef LWIP_HOOK_DHCP_PARSE_OPTION -#define LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, offset) do { LWIP_UNUSED_ARG(msg); } while(0) -#endif - -/** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using - * LWIP_RAND() (this overrides DHCP_GLOBAL_XID) - */ -#ifndef DHCP_CREATE_RAND_XID -#define DHCP_CREATE_RAND_XID 1 -#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 - -#if LWIP_DNS && LWIP_DHCP_MAX_DNS_SERVERS -#if DNS_MAX_SERVERS > LWIP_DHCP_MAX_DNS_SERVERS -#define LWIP_DHCP_PROVIDE_DNS_SERVERS LWIP_DHCP_MAX_DNS_SERVERS -#else -#define LWIP_DHCP_PROVIDE_DNS_SERVERS DNS_MAX_SERVERS -#endif -#else -#define LWIP_DHCP_PROVIDE_DNS_SERVERS 0 -#endif - -/** 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). */ -enum dhcp_option_idx { - DHCP_OPTION_IDX_OVERLOAD = 0, - DHCP_OPTION_IDX_MSG_TYPE, - DHCP_OPTION_IDX_SERVER_ID, - DHCP_OPTION_IDX_LEASE_TIME, - DHCP_OPTION_IDX_T1, - DHCP_OPTION_IDX_T2, - DHCP_OPTION_IDX_SUBNET_MASK, - DHCP_OPTION_IDX_ROUTER, -#if LWIP_DHCP_PROVIDE_DNS_SERVERS - DHCP_OPTION_IDX_DNS_SERVER, - DHCP_OPTION_IDX_DNS_SERVER_LAST = DHCP_OPTION_IDX_DNS_SERVER + LWIP_DHCP_PROVIDE_DNS_SERVERS - 1, -#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ -#if LWIP_DHCP_GET_NTP_SRV - DHCP_OPTION_IDX_NTP_SERVER, - DHCP_OPTION_IDX_NTP_SERVER_LAST = DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS - 1, -#endif /* LWIP_DHCP_GET_NTP_SRV */ - DHCP_OPTION_IDX_MAX -}; - -/** 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]; - -static u8_t dhcp_discover_request_options[] = { - DHCP_OPTION_SUBNET_MASK, - DHCP_OPTION_ROUTER, - DHCP_OPTION_BROADCAST -#if LWIP_DHCP_PROVIDE_DNS_SERVERS - , DHCP_OPTION_DNS_SERVER -#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ -#if LWIP_DHCP_GET_NTP_SRV - , DHCP_OPTION_NTP -#endif /* LWIP_DHCP_GET_NTP_SRV */ -}; - -#ifdef DHCP_GLOBAL_XID -static u32_t xid; -static u8_t xid_initialised; -#endif /* DHCP_GLOBAL_XID */ - -#define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0) -#define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1) -#define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0) -#define dhcp_clear_all_options(dhcp) (memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given))) -#define dhcp_get_option_value(dhcp, idx) (dhcp_rx_options_val[idx]) -#define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val)) - -static struct udp_pcb *dhcp_pcb; -static u8_t dhcp_pcb_refcount; - -/* 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, const 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 struct pbuf *dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type, u16_t *options_out_len); -/* add a DHCP option (type, then length in bytes) */ -static u16_t dhcp_option(u16_t options_out_len, u8_t *options, u8_t option_type, u8_t option_len); -/* add option values */ -static u16_t dhcp_option_byte(u16_t options_out_len, u8_t *options, u8_t value); -static u16_t dhcp_option_short(u16_t options_out_len, u8_t *options, u16_t value); -static u16_t dhcp_option_long(u16_t options_out_len, u8_t *options, u32_t value); -#if LWIP_NETIF_HOSTNAME -static u16_t dhcp_option_hostname(u16_t options_out_len, u8_t *options, struct netif *netif); -#endif /* LWIP_NETIF_HOSTNAME */ -/* always add the DHCP options trailer to end and pad */ -static void dhcp_option_trailer(u16_t options_out_len, u8_t *options, struct pbuf *p_out); - -/** Ensure DHCP PCB is allocated and bound */ -static err_t -dhcp_inc_pcb_refcount(void) -{ - if (dhcp_pcb_refcount == 0) { - LWIP_ASSERT("dhcp_inc_pcb_refcount(): memory leak", dhcp_pcb == NULL); - - /* allocate UDP PCB */ - dhcp_pcb = udp_new(); - - if (dhcp_pcb == NULL) { - return ERR_MEM; - } - - ip_set_option(dhcp_pcb, SOF_BROADCAST); - - /* set up local and remote port for the pcb -> listen on all interfaces on all src/dest IPs */ - udp_bind(dhcp_pcb, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_CLIENT); - udp_connect(dhcp_pcb, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_SERVER); - udp_recv(dhcp_pcb, dhcp_recv, NULL); - } - - dhcp_pcb_refcount++; - - return ERR_OK; -} - -/** Free DHCP PCB if the last netif stops using it */ -static void -dhcp_dec_pcb_refcount(void) -{ - LWIP_ASSERT("dhcp_pcb_refcount(): refcount error", (dhcp_pcb_refcount > 0)); - dhcp_pcb_refcount--; - - if (dhcp_pcb_refcount == 0) { - udp_remove(dhcp_pcb); - dhcp_pcb = NULL; - } -} - -/** - * 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 -dhcp_handle_nak(struct netif *netif) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - - 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)); - /* Change to a defined state - set this before assigning the address - to ensure the callback can use dhcp_supplied_address() */ - dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF); - /* remove IP address from interface (must no longer be used, as per RFC2131) */ - netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); - /* 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 -dhcp_check(struct netif *netif) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - 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_STATE_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")); - } - if (dhcp->tries < 255) { - dhcp->tries++; - } - msecs = 500; - dhcp->request_timeout = (u16_t)((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 -dhcp_handle_offer(struct netif *netif, struct dhcp_msg *msg_in) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - - 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)) { - dhcp->request_timeout = 0; /* stop timer */ - - ip_addr_set_ip4_u32(&dhcp->server_ip_addr, lwip_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(ip_2_ip4(&dhcp->server_ip_addr)))); - /* remember offered address */ - ip4_addr_copy(dhcp->offered_ip_addr, 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 -dhcp_select(struct netif *netif) -{ - struct dhcp *dhcp; - err_t result; - u16_t msecs; - u8_t i; - struct pbuf *p_out; - u16_t options_out_len; - - LWIP_ERROR("dhcp_select: netif != NULL", (netif != NULL), return ERR_ARG;); - dhcp = netif_dhcp_data(netif); - LWIP_ERROR("dhcp_select: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); - - 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_STATE_REQUESTING); - - /* create and initialize the DHCP message header */ - p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len); - if (p_out != NULL) { - struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); - - /* MUST request the offered IP address */ - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_REQUESTED_IP, 4); - options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_SERVER_ID, 4); - options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr)))); - - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); - for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { - options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); - } - -#if LWIP_NETIF_HOSTNAME - options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif); -#endif /* LWIP_NETIF_HOSTNAME */ - - LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REQUESTING, msg_out, DHCP_REQUEST, &options_out_len); - dhcp_option_trailer(options_out_len, msg_out->options, p_out); - - /* send broadcast to any DHCP server */ - result = udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY); - pbuf_free(p_out); - 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")); - result = ERR_MEM; - } - if (dhcp->tries < 255) { - dhcp->tries++; - } - msecs = (u16_t)((dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000); - dhcp->request_timeout = (u16_t)((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. - * Must be called once a minute (see @ref DHCP_COARSE_TIMER_SECS). - */ -void -dhcp_coarse_tmr(void) -{ - struct netif *netif; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); - /* iterate through all network interfaces */ - NETIF_FOREACH(netif) { - /* only act on DHCP configured interfaces */ - struct dhcp *dhcp = netif_dhcp_data(netif); - if ((dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)) { - /* compare lease time to expire timeout */ - if (dhcp->t0_timeout && (++dhcp->lease_used == dhcp->t0_timeout)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t0 timeout\n")); - /* this clients' lease time has expired */ - dhcp_release_and_stop(netif); - dhcp_start(netif); - /* timer is active (non zero), and triggers (zeroes) now? */ - } else if (dhcp->t2_rebind_time && (dhcp->t2_rebind_time-- == 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 (dhcp->t1_renew_time && (dhcp->t1_renew_time-- == 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); - } - } - } -} - -/** - * DHCP transaction timeout handling (this function must be called every 500ms, - * see @ref DHCP_FINE_TIMER_MSECS). - * - * A DHCP server is expected to respond within a short period of time. - * This timer checks whether an outstanding DHCP request is timed out. - */ -void -dhcp_fine_tmr(void) -{ - struct netif *netif; - /* loop through netif's */ - NETIF_FOREACH(netif) { - struct dhcp *dhcp = netif_dhcp_data(netif); - /* only act on DHCP configured interfaces */ - if (dhcp != NULL) { - /* timer is active (non zero), and is about to trigger now */ - if (dhcp->request_timeout > 1) { - dhcp->request_timeout--; - } else if (dhcp->request_timeout == 1) { - dhcp->request_timeout--; - /* { 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); - } - } - } -} - -/** - * 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 -dhcp_timeout(struct netif *netif) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n")); - /* back-off period has passed, or server selection timed out */ - if ((dhcp->state == DHCP_STATE_BACKING_OFF) || (dhcp->state == DHCP_STATE_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_STATE_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_and_stop(netif); - dhcp_start(netif); - } -#if DHCP_DOES_ARP_CHECK - /* received no ARP reply for the offered address (which is good) */ - } else if (dhcp->state == DHCP_STATE_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 */ - } else if (dhcp->state == DHCP_STATE_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 -dhcp_t1_timeout(struct netif *netif) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n")); - if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) || - (dhcp->state == DHCP_STATE_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_STATE_RENEWING, not DHCP_STATE_BOUND */ - dhcp_renew(netif); - /* Calculate next timeout */ - if (((dhcp->t2_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) { - dhcp->t1_renew_time = (u16_t)((dhcp->t2_timeout - dhcp->lease_used) / 2); - } - } -} - -/** - * The rebind period has timed out. - * - * @param netif the netif under DHCP control - */ -static void -dhcp_t2_timeout(struct netif *netif) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n")); - if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) || - (dhcp->state == DHCP_STATE_RENEWING) || (dhcp->state == DHCP_STATE_REBINDING)) { - /* 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_STATE_REBINDING, not DHCP_STATE_BOUND */ - dhcp_rebind(netif); - /* Calculate next timeout */ - if (((dhcp->t0_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) { - dhcp->t2_rebind_time = (u16_t)((dhcp->t0_timeout - dhcp->lease_used) / 2); - } - } -} - -/** - * Handle a DHCP ACK packet - * - * @param netif the netif under DHCP control - */ -static void -dhcp_handle_ack(struct netif *netif, struct dhcp_msg *msg_in) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - -#if LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV - u8_t n; -#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV */ -#if LWIP_DHCP_GET_NTP_SRV - ip4_addr_t ntp_server_addrs[LWIP_DHCP_MAX_NTP_SERVERS]; -#endif - - /* clear options we might not get from the ACK */ - ip4_addr_set_zero(&dhcp->offered_sn_mask); - ip4_addr_set_zero(&dhcp->offered_gw_addr); -#if LWIP_DHCP_BOOTP_FILE - ip4_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 (offered_t0_lease * 0.875 -> 87.5%)*/ - dhcp->offered_t2_rebind = (dhcp->offered_t0_lease * 7U) / 8U; - } - - /* (y)our internet address */ - ip4_addr_copy(dhcp->offered_ip_addr, msg_in->yiaddr); - -#if LWIP_DHCP_BOOTP_FILE - /* copy boot server address, - boot file name copied in dhcp_parse_reply if not overloaded */ - ip4_addr_copy(dhcp->offered_si_addr, 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, lwip_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, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER))); - } - -#if LWIP_DHCP_GET_NTP_SRV - /* NTP servers */ - for (n = 0; (n < LWIP_DHCP_MAX_NTP_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n); n++) { - ip4_addr_set_u32(&ntp_server_addrs[n], lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n))); - } - dhcp_set_ntp_servers(n, ntp_server_addrs); -#endif /* LWIP_DHCP_GET_NTP_SRV */ - -#if LWIP_DHCP_PROVIDE_DNS_SERVERS - /* DNS servers */ - for (n = 0; (n < LWIP_DHCP_PROVIDE_DNS_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) { - ip_addr_t dns_addr; - ip_addr_set_ip4_u32_val(dns_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n))); - dns_setserver(n, &dns_addr); - } -#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ -} - -/** - * @ingroup dhcp4 - * Set a statically allocated struct dhcp to work with. - * Using this prevents dhcp_start to allocate it using mem_malloc. - * - * @param netif the netif for which to set the struct dhcp - * @param dhcp (uninitialised) dhcp struct allocated by the application - */ -void -dhcp_set_struct(struct netif *netif, struct dhcp *dhcp) -{ - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ASSERT("netif != NULL", netif != NULL); - LWIP_ASSERT("dhcp != NULL", dhcp != NULL); - LWIP_ASSERT("netif already has a struct dhcp set", netif_dhcp_data(netif) == NULL); - - /* clear data structure */ - memset(dhcp, 0, sizeof(struct dhcp)); - /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */ - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp); -} - -/** - * @ingroup dhcp4 - * Removes a struct dhcp from a netif. - * - * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the - * struct dhcp since the memory is passed back to the heap. - * - * @param netif the netif from which to remove the struct dhcp - */ -void dhcp_cleanup(struct netif *netif) -{ - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ASSERT("netif != NULL", netif != NULL); - - if (netif_dhcp_data(netif) != NULL) { - mem_free(netif_dhcp_data(netif)); - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, NULL); - } -} - -/** - * @ingroup dhcp4 - * 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 -dhcp_start(struct netif *netif) -{ - struct dhcp *dhcp; - err_t result; - - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;); - LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;); - dhcp = netif_dhcp_data(netif); - 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)); - - /* 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(): mallocing 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_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_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_allocated != 0) { - dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */ - } - /* dhcp is cleared below, no need to reset flag*/ - } - - /* clear data structure */ - memset(dhcp, 0, sizeof(struct dhcp)); - /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */ - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n")); - - if (dhcp_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP PCB is allocated */ - return ERR_MEM; - } - dhcp->pcb_allocated = 1; - - if (!netif_is_link_up(netif)) { - /* set state INIT and wait for dhcp_network_changed() to call dhcp_discover() */ - dhcp_set_state(dhcp, DHCP_STATE_INIT); - return ERR_OK; - } - - /* (re)start the DHCP negotiation */ - result = dhcp_discover(netif); - if (result != ERR_OK) { - /* free resources allocated above */ - dhcp_release_and_stop(netif); - return ERR_MEM; - } - return result; -} - -/** - * @ingroup dhcp4 - * 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 -dhcp_inform(struct netif *netif) -{ - struct dhcp dhcp; - struct pbuf *p_out; - u16_t options_out_len; - - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - - if (dhcp_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP PCB is allocated */ - return; - } - - memset(&dhcp, 0, sizeof(struct dhcp)); - dhcp_set_state(&dhcp, DHCP_STATE_INFORMING); - - /* create and initialize the DHCP message header */ - p_out = dhcp_create_msg(netif, &dhcp, DHCP_INFORM, &options_out_len); - if (p_out != NULL) { - struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); - - LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, &dhcp, DHCP_STATE_INFORMING, msg_out, DHCP_INFORM, &options_out_len); - dhcp_option_trailer(options_out_len, msg_out->options, p_out); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); - - udp_sendto_if(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif); - - pbuf_free(p_out); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n")); - } - - dhcp_dec_pcb_refcount(); /* delete DHCP PCB if not needed any more */ -} - -/** Handle a possible change in the network configuration. - * - * This enters the REBOOTING state to verify that the currently bound - * address is still valid. - */ -void -dhcp_network_changed(struct netif *netif) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - - if (!dhcp) { - return; - } - switch (dhcp->state) { - case DHCP_STATE_REBINDING: - case DHCP_STATE_RENEWING: - case DHCP_STATE_BOUND: - case DHCP_STATE_REBOOTING: - dhcp->tries = 0; - dhcp_reboot(netif); - break; - case DHCP_STATE_OFF: - /* stay off */ - break; - default: - LWIP_ASSERT("invalid dhcp->state", dhcp->state <= DHCP_STATE_BACKING_OFF); - /* INIT/REQUESTING/CHECKING/BACKING_OFF restart with new 'rid' because the - state changes, SELECTING: continue with current 'rid' as we stay in the - same state */ -#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 */ - /* ensure we start with short timeouts, even if already discovering */ - dhcp->tries = 0; - dhcp_discover(netif); - break; - } -} - -#if DHCP_DOES_ARP_CHECK -/** - * Match an ARP reply with the offered IP address: - * check whether the offered IP address is not in use using ARP - * - * @param netif the network interface on which the reply was received - * @param addr The IP address we received a reply from - */ -void -dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr) -{ - struct dhcp *dhcp; - - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - dhcp = netif_dhcp_data(netif); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n")); - /* is a DHCP client doing an ARP check? */ - if ((dhcp != NULL) && (dhcp->state == DHCP_STATE_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 (ip4_addr_cmp(addr, &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 -dhcp_decline(struct netif *netif) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - err_t result; - u16_t msecs; - struct pbuf *p_out; - u16_t options_out_len; - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n")); - dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF); - /* create and initialize the DHCP message header */ - p_out = dhcp_create_msg(netif, dhcp, DHCP_DECLINE, &options_out_len); - if (p_out != NULL) { - struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_REQUESTED_IP, 4); - options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_BACKING_OFF, msg_out, DHCP_DECLINE, &options_out_len); - dhcp_option_trailer(options_out_len, msg_out->options, p_out); - - /* per section 4.4.4, broadcast DECLINE messages */ - result = udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY); - pbuf_free(p_out); - 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")); - result = ERR_MEM; - } - if (dhcp->tries < 255) { - dhcp->tries++; - } - msecs = 10 * 1000; - dhcp->request_timeout = (u16_t)((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 -dhcp_discover(struct netif *netif) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - err_t result = ERR_OK; - u16_t msecs; - u8_t i; - struct pbuf *p_out; - u16_t options_out_len; - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n")); - - ip4_addr_set_any(&dhcp->offered_ip_addr); - dhcp_set_state(dhcp, DHCP_STATE_SELECTING); - /* create and initialize the DHCP message header */ - p_out = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER, &options_out_len); - if (p_out != NULL) { - struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n")); - - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); - - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); - for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { - options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); - } - LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_SELECTING, msg_out, DHCP_DISCOVER, &options_out_len); - dhcp_option_trailer(options_out_len, msg_out->options, p_out); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER)\n")); - udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); - pbuf_free(p_out); - 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")); - } - if (dhcp->tries < 255) { - 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 = (u16_t)((dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000); - dhcp->request_timeout = (u16_t)((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 -dhcp_bind(struct netif *netif) -{ - u32_t timeout; - struct dhcp *dhcp; - ip4_addr_t sn_mask, gw_addr; - LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;); - dhcp = netif_dhcp_data(netif); - 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)); - - /* reset time used of lease */ - dhcp->lease_used = 0; - - if (dhcp->offered_t0_lease != 0xffffffffUL) { - /* set renewal period timer */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t0 renewal timer %"U32_F" secs\n", dhcp->offered_t0_lease)); - timeout = (dhcp->offered_t0_lease + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; - if (timeout > 0xffff) { - timeout = 0xffff; - } - dhcp->t0_timeout = (u16_t)timeout; - if (dhcp->t0_timeout == 0) { - dhcp->t0_timeout = 1; - } - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t0_lease * 1000)); - } - - /* 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)); - dhcp->t1_renew_time = dhcp->t1_timeout; - } - /* 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)); - dhcp->t2_rebind_time = dhcp->t2_timeout; - } - - /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. */ - if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) { - dhcp->t1_timeout = 0; - } - - if (dhcp->subnet_mask_given) { - /* copy offered network mask */ - ip4_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(0xff000000UL)); - } else if (first_octet >= 192) { - ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL)); - } else { - ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL)); - } - } - - ip4_addr_copy(gw_addr, dhcp->offered_gw_addr); - /* gateway address not given? */ - if (ip4_addr_isany_val(gw_addr)) { - /* copy network address */ - ip4_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(0x00000001UL)); - } - -#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 */ - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F" SN: 0x%08"X32_F" GW: 0x%08"X32_F"\n", - ip4_addr_get_u32(&dhcp->offered_ip_addr), ip4_addr_get_u32(&sn_mask), ip4_addr_get_u32(&gw_addr))); - /* netif is now bound to DHCP leased address - set this before assigning the address - to ensure the callback can use dhcp_supplied_address() */ - dhcp_set_state(dhcp, DHCP_STATE_BOUND); - - netif_set_addr(netif, &dhcp->offered_ip_addr, &sn_mask, &gw_addr); - /* interface is used by routing now that an address is set */ -} - -/** - * @ingroup dhcp4 - * Renew an existing DHCP lease at the involved DHCP server. - * - * @param netif network interface which must renew its lease - */ -err_t -dhcp_renew(struct netif *netif) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - err_t result; - u16_t msecs; - u8_t i; - struct pbuf *p_out; - u16_t options_out_len; - - LWIP_ASSERT_CORE_LOCKED(); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n")); - dhcp_set_state(dhcp, DHCP_STATE_RENEWING); - - /* create and initialize the DHCP message header */ - p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len); - if (p_out != NULL) { - struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); - - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); - for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { - options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); - } - -#if LWIP_NETIF_HOSTNAME - options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif); -#endif /* LWIP_NETIF_HOSTNAME */ - - LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_RENEWING, msg_out, DHCP_REQUEST, &options_out_len); - dhcp_option_trailer(options_out_len, msg_out->options, p_out); - - result = udp_sendto_if(dhcp_pcb, p_out, &dhcp->server_ip_addr, LWIP_IANA_PORT_DHCP_SERVER, netif); - pbuf_free(p_out); - - 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")); - result = ERR_MEM; - } - if (dhcp->tries < 255) { - dhcp->tries++; - } - /* back-off on retries, but to a maximum of 20 seconds */ - msecs = (u16_t)(dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000); - dhcp->request_timeout = (u16_t)((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 -dhcp_rebind(struct netif *netif) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - err_t result; - u16_t msecs; - u8_t i; - struct pbuf *p_out; - u16_t options_out_len; - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n")); - dhcp_set_state(dhcp, DHCP_STATE_REBINDING); - - /* create and initialize the DHCP message header */ - p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len); - if (p_out != NULL) { - struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); - - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); - for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { - options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); - } - -#if LWIP_NETIF_HOSTNAME - options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif); -#endif /* LWIP_NETIF_HOSTNAME */ - - LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REBINDING, msg_out, DHCP_DISCOVER, &options_out_len); - dhcp_option_trailer(options_out_len, msg_out->options, p_out); - - /* broadcast to server */ - result = udp_sendto_if(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif); - pbuf_free(p_out); - 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")); - result = ERR_MEM; - } - if (dhcp->tries < 255) { - dhcp->tries++; - } - msecs = (u16_t)(dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000); - dhcp->request_timeout = (u16_t)((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 -dhcp_reboot(struct netif *netif) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - err_t result; - u16_t msecs; - u8_t i; - struct pbuf *p_out; - u16_t options_out_len; - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n")); - dhcp_set_state(dhcp, DHCP_STATE_REBOOTING); - - /* create and initialize the DHCP message header */ - p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len); - if (p_out != NULL) { - struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN_MIN_REQUIRED); - - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_REQUESTED_IP, 4); - options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); - for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { - options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); - } - -#if LWIP_NETIF_HOSTNAME - options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif); -#endif /* LWIP_NETIF_HOSTNAME */ - - LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REBOOTING, msg_out, DHCP_REQUEST, &options_out_len); - dhcp_option_trailer(options_out_len, msg_out->options, p_out); - - /* broadcast to server */ - result = udp_sendto_if(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif); - pbuf_free(p_out); - 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")); - result = ERR_MEM; - } - if (dhcp->tries < 255) { - dhcp->tries++; - } - msecs = (u16_t)(dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000); - dhcp->request_timeout = (u16_t)((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; -} - -/** - * @ingroup dhcp4 - * Release a DHCP lease and stop DHCP statemachine (and AUTOIP if LWIP_DHCP_AUTOIP_COOP). - * - * @param netif network interface - */ -void -dhcp_release_and_stop(struct netif *netif) -{ - struct dhcp *dhcp = netif_dhcp_data(netif); - ip_addr_t server_ip_addr; - - LWIP_ASSERT_CORE_LOCKED(); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release_and_stop()\n")); - if (dhcp == NULL) { - return; - } - - /* already off? -> nothing to do */ - if (dhcp->state == DHCP_STATE_OFF) { - return; - } - - ip_addr_copy(server_ip_addr, dhcp->server_ip_addr); - - /* clean old DHCP offer */ - ip_addr_set_zero_ip4(&dhcp->server_ip_addr); - ip4_addr_set_zero(&dhcp->offered_ip_addr); - ip4_addr_set_zero(&dhcp->offered_sn_mask); - ip4_addr_set_zero(&dhcp->offered_gw_addr); -#if LWIP_DHCP_BOOTP_FILE - ip4_addr_set_zero(&dhcp->offered_si_addr); -#endif /* LWIP_DHCP_BOOTP_FILE */ - dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; - dhcp->t1_renew_time = dhcp->t2_rebind_time = dhcp->lease_used = dhcp->t0_timeout = 0; - - /* send release message when current IP was assigned via DHCP */ - if (dhcp_supplied_address(netif)) { - /* create and initialize the DHCP message header */ - struct pbuf *p_out; - u16_t options_out_len; - p_out = dhcp_create_msg(netif, dhcp, DHCP_RELEASE, &options_out_len); - if (p_out != NULL) { - struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; - options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_SERVER_ID, 4); - options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&server_ip_addr)))); - - LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, dhcp->state, msg_out, DHCP_RELEASE, &options_out_len); - dhcp_option_trailer(options_out_len, msg_out->options, p_out); - - udp_sendto_if(dhcp_pcb, p_out, &server_ip_addr, LWIP_IANA_PORT_DHCP_SERVER, netif); - pbuf_free(p_out); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_STATE_OFF\n")); - } else { - /* sending release failed, but that's not a problem since the correct behaviour of dhcp does not rely on release */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n")); - } - } - - /* remove IP address from interface (prevents routing from selecting this interface) */ - netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); - -#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_set_state(dhcp, DHCP_STATE_OFF); - - if (dhcp->pcb_allocated != 0) { - dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */ - dhcp->pcb_allocated = 0; - } -} - -/** - * @ingroup dhcp4 - * This function calls dhcp_release_and_stop() internally. - * @deprecated Use dhcp_release_and_stop() instead. - */ -err_t -dhcp_release(struct netif *netif) -{ - dhcp_release_and_stop(netif); - return ERR_OK; -} - -/** - * @ingroup dhcp4 - * This function calls dhcp_release_and_stop() internally. - * @deprecated Use dhcp_release_and_stop() instead. - */ -void -dhcp_stop(struct netif *netif) -{ - dhcp_release_and_stop(netif); -} - -/* - * Set the DHCP state of a DHCP client. - * - * If the state changed, reset the number of tries. - */ -static void -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 u16_t -dhcp_option(u16_t options_out_len, u8_t *options, u8_t option_type, u8_t option_len) -{ - LWIP_ASSERT("dhcp_option: options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN); - options[options_out_len++] = option_type; - options[options_out_len++] = option_len; - return options_out_len; -} -/* - * Concatenate a single byte to the outgoing DHCP message. - * - */ -static u16_t -dhcp_option_byte(u16_t options_out_len, u8_t *options, u8_t value) -{ - LWIP_ASSERT("dhcp_option_byte: options_out_len < DHCP_OPTIONS_LEN", options_out_len < DHCP_OPTIONS_LEN); - options[options_out_len++] = value; - return options_out_len; -} - -static u16_t -dhcp_option_short(u16_t options_out_len, u8_t *options, u16_t value) -{ - LWIP_ASSERT("dhcp_option_short: options_out_len + 2 <= DHCP_OPTIONS_LEN", options_out_len + 2U <= DHCP_OPTIONS_LEN); - options[options_out_len++] = (u8_t)((value & 0xff00U) >> 8); - options[options_out_len++] = (u8_t) (value & 0x00ffU); - return options_out_len; -} - -static u16_t -dhcp_option_long(u16_t options_out_len, u8_t *options, u32_t value) -{ - LWIP_ASSERT("dhcp_option_long: options_out_len + 4 <= DHCP_OPTIONS_LEN", options_out_len + 4U <= DHCP_OPTIONS_LEN); - options[options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24); - options[options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16); - options[options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8); - options[options_out_len++] = (u8_t)((value & 0x000000ffUL)); - return options_out_len; -} - -#if LWIP_NETIF_HOSTNAME -static u16_t -dhcp_option_hostname(u16_t options_out_len, u8_t *options, struct netif *netif) -{ - if (netif->hostname != NULL) { - size_t namelen = strlen(netif->hostname); - if (namelen > 0) { - size_t len; - const char *p = netif->hostname; - /* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME - and 1 byte for trailer) */ - size_t available = DHCP_OPTIONS_LEN - options_out_len - 3; - LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available); - len = LWIP_MIN(namelen, available); - LWIP_ASSERT("DHCP: hostname is too long!", len <= 0xFF); - options_out_len = dhcp_option(options_out_len, options, DHCP_OPTION_HOSTNAME, (u8_t)len); - while (len--) { - options_out_len = dhcp_option_byte(options_out_len, options, *p++); - } - } - } - return options_out_len; -} -#endif /* LWIP_NETIF_HOSTNAME */ - -/** - * 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 contiguous piece of memory, and - * use that further on. - * - */ -static err_t -dhcp_parse_reply(struct pbuf *p, struct dhcp *dhcp) -{ - 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; - struct dhcp_msg *msg_in; -#if LWIP_DHCP_BOOTP_FILE - int file_overloaded = 0; -#endif - - LWIP_UNUSED_ARG(dhcp); - - /* 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; - } - 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 = (u16_t)(options_idx - q->len); - options_idx_max = (u16_t)(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) && (offset < offset_max) && (options[offset] != DHCP_OPTION_END)) { - u8_t op = options[offset]; - u8_t len; - u8_t decode_len = 0; - int decode_idx = -1; - u16_t val_offset = (u16_t)(offset + 2); - if (val_offset < offset) { - /* overflow */ - return ERR_BUF; - } - /* 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 */ - break; - case (DHCP_OPTION_SUBNET_MASK): - LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_SUBNET_MASK; - break; - case (DHCP_OPTION_ROUTER): - decode_len = 4; /* only copy the first given router */ - LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_ROUTER; - break; -#if LWIP_DHCP_PROVIDE_DNS_SERVERS - case (DHCP_OPTION_DNS_SERVER): - /* special case: there might be more than one server */ - LWIP_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;); - /* limit number of DNS servers */ - decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS); - LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_DNS_SERVER; - break; -#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ - case (DHCP_OPTION_LEASE_TIME): - LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_LEASE_TIME; - break; -#if LWIP_DHCP_GET_NTP_SRV - case (DHCP_OPTION_NTP): - /* special case: there might be more than one server */ - LWIP_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;); - /* limit number of NTP servers */ - decode_len = LWIP_MIN(len, 4 * LWIP_DHCP_MAX_NTP_SERVERS); - LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_NTP_SERVER; - break; -#endif /* LWIP_DHCP_GET_NTP_SRV*/ - case (DHCP_OPTION_OVERLOAD): - LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); - /* decode overload only in options, not in file/sname: invalid packet */ - LWIP_ERROR("overload in file/sname", options_idx == DHCP_OPTIONS_OFS, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_OVERLOAD; - break; - case (DHCP_OPTION_MESSAGE_TYPE): - LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_MSG_TYPE; - break; - case (DHCP_OPTION_SERVER_ID): - LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_SERVER_ID; - break; - case (DHCP_OPTION_T1): - LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_T1; - break; - case (DHCP_OPTION_T2): - LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_T2; - break; - default: - decode_len = 0; - LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", (u16_t)op)); - LWIP_HOOK_DHCP_PARSE_OPTION(ip_current_netif(), dhcp, dhcp->state, msg_in, - dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) ? (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) : 0, - op, len, q, val_offset); - break; - } - if (op == DHCP_OPTION_PAD) { - offset++; - } else { - if (offset + len + 2 > 0xFFFF) { - /* overflow */ - return ERR_BUF; - } - offset = (u16_t)(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); - if (!dhcp_option_given(dhcp, decode_idx)) { - copy_len = LWIP_MIN(decode_len, 4); - if (pbuf_copy_partial(q, &value, copy_len, val_offset) != copy_len) { - return ERR_BUF; - } - if (decode_len > 4) { - /* decode more than one u32_t */ - u16_t next_val_offset; - LWIP_ERROR("decode_len %% 4 == 0", decode_len % 4 == 0, return ERR_VAL;); - dhcp_got_option(dhcp, decode_idx); - dhcp_set_option_value(dhcp, decode_idx, lwip_htonl(value)); - decode_len = (u8_t)(decode_len - 4); - next_val_offset = (u16_t)(val_offset + 4); - if (next_val_offset < val_offset) { - /* overflow */ - return ERR_BUF; - } - val_offset = next_val_offset; - decode_idx++; - goto decode_next; - } else if (decode_len == 4) { - value = lwip_ntohl(value); - } else { - LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;); - value = ((u8_t *)&value)[0]; - } - dhcp_got_option(dhcp, decode_idx); - dhcp_set_option_value(dhcp, decode_idx, value); - } - } - } - if (offset >= q->len) { - offset = (u16_t)(offset - q->len); - offset_max = (u16_t)(offset_max - q->len); - if (offset < offset_max) { - q = q->next; - LWIP_ERROR("next pbuf was null", q != NULL, return ERR_VAL;); - options = (u8_t *)q->payload; - } else { - /* We've run out of bytes, probably no end marker. Don't proceed. */ - return ERR_BUF; - } - } - } - /* 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 (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; -#if LWIP_DHCP_BOOTP_FILE - file_overloaded = 1; -#endif - 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; - } -#if LWIP_DHCP_BOOTP_FILE - if (!file_overloaded) { - /* 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) */ - if (pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS) != (DHCP_FILE_LEN-1)) { - return ERR_BUF; - } - /* make sure the string is really NULL-terminated */ - dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0; - } -#endif /* LWIP_DHCP_BOOTP_FILE */ - return ERR_OK; -} - -/** - * If an incoming DHCP message is in response to us, then trigger the state machine - */ -static void -dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) -{ - struct netif *netif = ip_current_input_netif(); - struct dhcp *dhcp = netif_dhcp_data(netif); - struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; - u8_t msg_type; - u8_t i; - struct dhcp_msg *msg_in; - - LWIP_UNUSED_ARG(arg); - - /* Caught DHCP message from netif that does not have DHCP enabled? -> not interested */ - if ((dhcp == NULL) || (dhcp->pcb_allocated == 0)) { - goto free_pbuf_and_return; - } - - LWIP_ASSERT("invalid server address type", IP_IS_V4(addr)); - - 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(ip_2_ip4(addr)), ip4_addr2_16(ip_2_ip4(addr)), ip4_addr3_16(ip_2_ip4(addr)), ip4_addr4_16(ip_2_ip4(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); - - 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 < LWIP_MIN(DHCP_CHADDR_LEN, NETIF_MAX_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 (lwip_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", lwip_ntohl(reply_msg->xid), dhcp->xid)); - goto free_pbuf_and_return; - } - /* option fields could be unfold? */ - if (dhcp_parse_reply(p, dhcp) != 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; - } - - msg_in = (struct dhcp_msg *)p->payload; - /* 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_STATE_REQUESTING) { - dhcp_handle_ack(netif, msg_in); -#if DHCP_DOES_ARP_CHECK - if ((netif->flags & NETIF_FLAG_ETHARP) != 0) { - /* check if the acknowledged lease address is already in use */ - dhcp_check(netif); - } else { - /* bind interface to the acknowledged lease address */ - dhcp_bind(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_STATE_REBOOTING) || (dhcp->state == DHCP_STATE_REBINDING) || - (dhcp->state == DHCP_STATE_RENEWING)) { - dhcp_handle_ack(netif, msg_in); - dhcp_bind(netif); - } - } - /* received a DHCP_NAK in appropriate state? */ - else if ((msg_type == DHCP_NAK) && - ((dhcp->state == DHCP_STATE_REBOOTING) || (dhcp->state == DHCP_STATE_REQUESTING) || - (dhcp->state == DHCP_STATE_REBINDING) || (dhcp->state == DHCP_STATE_RENEWING ))) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n")); - dhcp_handle_nak(netif); - } - /* received a DHCP_OFFER in DHCP_STATE_SELECTING state? */ - else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_STATE_SELECTING)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_STATE_SELECTING state\n")); - /* remember offered lease */ - dhcp_handle_offer(netif, msg_in); - } - -free_pbuf_and_return: - 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 struct pbuf * -dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type, u16_t *options_out_len) -{ - u16_t i; - struct pbuf *p_out; - struct dhcp_msg *msg_out; - u16_t options_out_len_loc; - -#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 */ -#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) - static u32_t xid; -#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ - static u32_t xid = 0xABCD0000; -#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ -#else - if (!xid_initialised) { - xid = DHCP_GLOBAL_XID; - xid_initialised = !xid_initialised; - } -#endif - LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return NULL;); - LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return NULL;); - p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); - if (p_out == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_create_msg(): could not allocate pbuf\n")); - return NULL; - } - LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg", - (p_out->len >= sizeof(struct dhcp_msg))); - - /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER */ - if ((message_type != DHCP_REQUEST) || (dhcp->state == DHCP_STATE_REBOOTING)) { - /* reuse transaction identifier in retransmissions */ - if (dhcp->tries == 0) { -#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) - xid = LWIP_RAND(); -#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ - xid++; -#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ - } - dhcp->xid = xid; - } - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, - ("transaction id xid(%"X32_F")\n", xid)); - - msg_out = (struct dhcp_msg *)p_out->payload; - memset(msg_out, 0, sizeof(struct dhcp_msg)); - - msg_out->op = DHCP_BOOTREQUEST; - /* @todo: make link layer independent */ - msg_out->htype = LWIP_IANA_HWTYPE_ETHERNET; - msg_out->hlen = netif->hwaddr_len; - msg_out->xid = lwip_htonl(dhcp->xid); - /* we don't need the broadcast flag since we can receive unicast traffic - before being fully configured! */ - /* set ciaddr to netif->ip_addr based on message_type and state */ - if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) || (message_type == DHCP_RELEASE) || - ((message_type == DHCP_REQUEST) && /* DHCP_STATE_BOUND not used for sending! */ - ((dhcp->state == DHCP_STATE_RENEWING) || dhcp->state == DHCP_STATE_REBINDING))) { - ip4_addr_copy(msg_out->ciaddr, *netif_ip4_addr(netif)); - } - for (i = 0; i < LWIP_MIN(DHCP_CHADDR_LEN, NETIF_MAX_HWADDR_LEN); i++) { - /* copy netif hardware address (padded with zeroes through memset already) */ - msg_out->chaddr[i] = netif->hwaddr[i]; - } - msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE); - /* Add option MESSAGE_TYPE */ - options_out_len_loc = dhcp_option(0, msg_out->options, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); - options_out_len_loc = dhcp_option_byte(options_out_len_loc, msg_out->options, message_type); - if (options_out_len) { - *options_out_len = options_out_len_loc; - } - return p_out; -} - -/** - * Add a DHCP message trailer - * - * Adds the END option to the DHCP message, and if - * necessary, up to three padding bytes. - */ -static void -dhcp_option_trailer(u16_t options_out_len, u8_t *options, struct pbuf *p_out) -{ - options[options_out_len++] = DHCP_OPTION_END; - /* packet is too small, or not 4 byte aligned? */ - while (((options_out_len < DHCP_MIN_OPTIONS_LEN) || (options_out_len & 3)) && - (options_out_len < DHCP_OPTIONS_LEN)) { - /* add a fill/padding byte */ - options[options_out_len++] = 0; - } - /* shrink the pbuf to the actual content length */ - pbuf_realloc(p_out, (u16_t)(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + options_out_len)); -} - -/** check if DHCP supplied netif->ip_addr - * - * @param netif the netif to check - * @return 1 if DHCP supplied netif->ip_addr (states BOUND or RENEWING), - * 0 otherwise - */ -u8_t -dhcp_supplied_address(const struct netif *netif) -{ - if ((netif != NULL) && (netif_dhcp_data(netif) != NULL)) { - struct dhcp *dhcp = netif_dhcp_data(netif); - return (dhcp->state == DHCP_STATE_BOUND) || (dhcp->state == DHCP_STATE_RENEWING) || - (dhcp->state == DHCP_STATE_REBINDING); - } - return 0; -} - -#endif /* LWIP_IPV4 && LWIP_DHCP */ diff --git a/core/c/core/ipv4/etharp.c b/core/c/core/ipv4/etharp.c deleted file mode 100755 index 570aaa3..0000000 --- a/core/c/core/ipv4/etharp.c +++ /dev/null @@ -1,1204 +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_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/etharp.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" -#include "lwip/prot/iana.h" -#include "netif/ethernet.h" - -#include - -#ifdef LWIP_HOOK_FILENAME -#include LWIP_HOOK_FILENAME -#endif - -/** 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_UNICAST (ARP_MAXAGE - 30) -#define ARP_AGE_REREQUEST_USED_BROADCAST (ARP_MAXAGE - 15) - -/** the time an ARP entry stays pending after first request, - * for ARP_TMR_INTERVAL = 1000, this is - * 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 5 - -/** ARP states */ -enum etharp_state { - ETHARP_STATE_EMPTY = 0, - ETHARP_STATE_PENDING, - ETHARP_STATE_STABLE, - ETHARP_STATE_STABLE_REREQUESTING_1, - ETHARP_STATE_STABLE_REREQUESTING_2 -#if ETHARP_SUPPORT_STATIC_ENTRIES - , ETHARP_STATE_STATIC -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ -}; - -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 */ - ip4_addr_t ipaddr; - struct netif *netif; - struct eth_addr ethaddr; - u16_t ctime; - u8_t state; -}; - -static struct etharp_entry arp_table[ARP_TABLE_SIZE]; - -#if !LWIP_NETIF_HWADDRHINT -static netif_addr_idx_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 -#if ETHARP_SUPPORT_STATIC_ENTRIES -#define ETHARP_FLAG_STATIC_ENTRY 4 -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - -#if LWIP_NETIF_HWADDRHINT -#define ETHARP_SET_ADDRHINT(netif, addrhint) do { if (((netif) != NULL) && ((netif)->hints != NULL)) { \ - (netif)->hints->addr_hint = (addrhint); }} while(0) -#else /* LWIP_NETIF_HWADDRHINT */ -#define ETHARP_SET_ADDRHINT(netif, addrhint) (etharp_cached_entry = (addrhint)) -#endif /* LWIP_NETIF_HWADDRHINT */ - - -/* Check for maximum ARP_TABLE_SIZE */ -#if (ARP_TABLE_SIZE > NETIF_ADDR_IDX_MAX) -#error "ARP_TABLE_SIZE must fit in an s16_t, you have to reduce it in your lwipopts.h" -#endif - - -static err_t etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr *hw_dst_addr); -static err_t etharp_raw(struct netif *netif, - const struct eth_addr *ethsrc_addr, const struct eth_addr *ethdst_addr, - const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr, - const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr, - const u16_t opcode); - -#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); - 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 -etharp_free_entry(int i) -{ - /* remove from SNMP ARP index tree */ - mib2_remove_arp_entry(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_free_entry: 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; -#ifdef LWIP_DEBUG - /* for debugging, clean out the complete entry */ - arp_table[i].ctime = 0; - arp_table[i].netif = NULL; - ip4_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 ARP_TMR_INTERVAL milliseconds (1 second), - * in order to expire entries in the ARP table. - */ -void -etharp_tmr(void) -{ - int 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 - && (state != ETHARP_STATE_STATIC) -#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 %d.\n", - arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", i)); - /* clean up entries that have just been expired */ - etharp_free_entry(i); - } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_1) { - /* Don't send more than one request every 2 seconds. */ - arp_table[i].state = ETHARP_STATE_STABLE_REREQUESTING_2; - } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_2) { - /* Reset state to stable, so that the next transmitted packet will - re-send an ARP request. */ - arp_table[i].state = ETHARP_STATE_STABLE; - } else if (arp_table[i].state == ETHARP_STATE_PENDING) { - /* still pending, resend an ARP query */ - etharp_request(arp_table[i].netif, &arp_table[i].ipaddr); - } - } - } -} - -/** - * 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 @ref etharp_state - * @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 s16_t -etharp_find_entry(const ip4_addr_t *ipaddr, u8_t flags, struct netif *netif) -{ - s16_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; - s16_t empty = ARP_TABLE_SIZE; - s16_t i = 0; - /* oldest entry with packets on queue */ - s16_t old_queue = ARP_TABLE_SIZE; - /* its age */ - u16_t age_queue = 0, age_pending = 0, age_stable = 0; - - LWIP_UNUSED_ARG(netif); - - /** - * 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, ("etharp_find_entry: found empty entry %d\n", (int)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 && ip4_addr_cmp(ipaddr, &arp_table[i].ipaddr) -#if ETHARP_TABLE_MATCH_NETIF - && ((netif == NULL) || (netif == arp_table[i].netif)) -#endif /* ETHARP_TABLE_MATCH_NETIF */ - ) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %d\n", (int)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 (state < ETHARP_STATE_STATIC) -#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, ("etharp_find_entry: no empty entry found and not allowed to recycle\n")); - return (s16_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, ("etharp_find_entry: selecting empty entry %d\n", (int)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, ("etharp_find_entry: selecting oldest stable entry %d\n", (int)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, ("etharp_find_entry: selecting oldest pending entry %d (without queue)\n", (int)i)); - /* 4) found recyclable pending entry with queued packets? */ - } else if (old_queue < ARP_TABLE_SIZE) { - /* recycle oldest pending (queued packets are free in etharp_free_entry) */ - i = old_queue; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %d, freeing packet queue %p\n", (int)i, (void *)(arp_table[i].q))); - /* no empty or recyclable entries found */ - } else { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n")); - return (s16_t)ERR_MEM; - } - - /* { empty or recyclable entry found } */ - LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); - etharp_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 */ - ip4_addr_copy(arp_table[i].ipaddr, *ipaddr); - } - arp_table[i].ctime = 0; -#if ETHARP_TABLE_MATCH_NETIF - arp_table[i].netif = netif; -#endif /* ETHARP_TABLE_MATCH_NETIF */ - return (s16_t)i; -} - -/** - * 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 @ref etharp_state - * - * @return - * - ERR_OK Successfully 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 -etharp_update_arp_entry(struct netif *netif, const ip4_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags) -{ - s16_t i; - LWIP_ASSERT("netif->hwaddr_len == ETH_HWADDR_LEN", netif->hwaddr_len == ETH_HWADDR_LEN); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_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), - (u16_t)ethaddr->addr[0], (u16_t)ethaddr->addr[1], (u16_t)ethaddr->addr[2], - (u16_t)ethaddr->addr[3], (u16_t)ethaddr->addr[4], (u16_t)ethaddr->addr[5])); - /* non-unicast address? */ - if (ip4_addr_isany(ipaddr) || - ip4_addr_isbroadcast(ipaddr, netif) || - ip4_addr_ismulticast(ipaddr)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: will not add non-unicast IP address to ARP cache\n")); - return ERR_ARG; - } - /* find or create ARP entry */ - i = etharp_find_entry(ipaddr, flags, netif); - /* 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].state = ETHARP_STATE_STATIC; - } else if (arp_table[i].state == ETHARP_STATE_STATIC) { - /* found entry is a static type, don't overwrite it */ - return ERR_VAL; - } else -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - { - /* mark it stable */ - arp_table[i].state = ETHARP_STATE_STABLE; - } - - /* record network interface */ - arp_table[i].netif = netif; - /* insert in SNMP ARP index tree */ - mib2_add_arp_entry(netif, &arp_table[i].ipaddr); - - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", i)); - /* update address */ - SMEMCPY(&arp_table[i].ethaddr, ethaddr, ETH_HWADDR_LEN); - /* 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 */ - ethernet_output(netif, p, (struct eth_addr *)(netif->hwaddr), ethaddr, ETHTYPE_IP); - /* 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(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr) -{ - struct netif *netif; - LWIP_ASSERT_CORE_LOCKED(); - 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), - (u16_t)ethaddr->addr[0], (u16_t)ethaddr->addr[1], (u16_t)ethaddr->addr[2], - (u16_t)ethaddr->addr[3], (u16_t)ethaddr->addr[4], (u16_t)ethaddr->addr[5])); - - netif = ip4_route(ipaddr); - if (netif == NULL) { - return ERR_RTE; - } - - return etharp_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(const ip4_addr_t *ipaddr) -{ - s16_t i; - LWIP_ASSERT_CORE_LOCKED(); - 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 = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY, NULL); - /* bail out if no entry could be found */ - if (i < 0) { - return (err_t)i; - } - - if (arp_table[i].state != ETHARP_STATE_STATIC) { - /* entry wasn't a static entry, cannot remove it */ - return ERR_ARG; - } - /* entry found, free it */ - etharp_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 -etharp_cleanup_netif(struct netif *netif) -{ - int 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)) { - etharp_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 - */ -ssize_t -etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr, - struct eth_addr **eth_ret, const ip4_addr_t **ip_ret) -{ - s16_t i; - - LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL", - eth_ret != NULL && ip_ret != NULL); - - LWIP_UNUSED_ARG(netif); - - i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY, netif); - 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; -} - -/** - * Possibility to iterate over stable ARP table entries - * - * @param i entry number, 0 to ARP_TABLE_SIZE - * @param ipaddr return value: IP address - * @param netif return value: points to interface - * @param eth_ret return value: ETH address - * @return 1 on valid index, 0 otherwise - */ -int -etharp_get_entry(size_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth_addr **eth_ret) -{ - LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); - LWIP_ASSERT("netif != NULL", netif != NULL); - LWIP_ASSERT("eth_ret != NULL", eth_ret != NULL); - - if ((i < ARP_TABLE_SIZE) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { - *ipaddr = &arp_table[i].ipaddr; - *netif = arp_table[i].netif; - *eth_ret = &arp_table[i].ethaddr; - return 1; - } else { - return 0; - } -} - -/** - * 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 p The ARP packet that arrived on netif. Is freed by this function. - * @param netif The lwIP network interface on which the ARP packet pbuf arrived. - * - * @see pbuf_free() - */ -void -etharp_input(struct pbuf *p, struct netif *netif) -{ - struct etharp_hdr *hdr; - /* these are aligned properly, whereas the ARP header fields might not be */ - ip4_addr_t sipaddr, dipaddr; - u8_t for_us; - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - - hdr = (struct etharp_hdr *)p->payload; - - /* RFC 826 "Packet Reception": */ - if ((hdr->hwtype != PP_HTONS(LWIP_IANA_HWTYPE_ETHERNET)) || - (hdr->hwlen != ETH_HWADDR_LEN) || - (hdr->protolen != sizeof(ip4_addr_t)) || - (hdr->proto != PP_HTONS(ETHTYPE_IP))) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("etharp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", - hdr->hwtype, (u16_t)hdr->hwlen, hdr->proto, (u16_t)hdr->protolen)); - 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 continuously 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 ip4_addr_wordaligned to aligned ip4_addr, to support compilers without - * structure packing (not using structure copy which breaks strict-aliasing rules). */ - IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr); - IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr); - - /* this interface is not configured? */ - if (ip4_addr_isany_val(*netif_ip4_addr(netif))) { - for_us = 0; - } else { - /* ARP packet directed to us? */ - for_us = (u8_t)ip4_addr_cmp(&dipaddr, netif_ip4_addr(netif)); - } - - /* 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 */ - etharp_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 possibly send out an IP packet that was queued on it. */ - - LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP request\n")); - /* ARP request for our address? */ - if (for_us) { - /* send ARP response */ - etharp_raw(netif, - (struct eth_addr *)netif->hwaddr, &hdr->shwaddr, - (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif), - &hdr->shwaddr, &sipaddr, - ARP_REPLY); - /* we are not configured? */ - } else if (ip4_addr_isany_val(*netif_ip4_addr(netif))) { - /* { for_us == 0 and netif->ip_addr.addr == 0 } */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_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_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_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_input: ARP unknown opcode type %"S16_F"\n", lwip_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 -etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, netif_addr_idx_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) { - if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_BROADCAST) { - /* issue a standard request using broadcast */ - if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) { - arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1; - } - } else if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_UNICAST) { - /* issue a unicast request (for 15 seconds) to prevent unnecessary broadcast */ - if (etharp_request_dst(netif, &arp_table[arp_idx].ipaddr, &arp_table[arp_idx].ethaddr) == ERR_OK) { - arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1; - } - } - } - - return ethernet_output(netif, q, (struct eth_addr *)(netif->hwaddr), &arp_table[arp_idx].ethaddr, ETHTYPE_IP); -} - -/** - * 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 ethernet_output(). - */ -err_t -etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) -{ - const struct eth_addr *dest; - struct eth_addr mcastaddr; - const ip4_addr_t *dst_addr = ipaddr; - - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ASSERT("netif != NULL", netif != NULL); - LWIP_ASSERT("q != NULL", q != NULL); - LWIP_ASSERT("ipaddr != NULL", ipaddr != 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 (ip4_addr_isbroadcast(ipaddr, netif)) { - /* broadcast on Ethernet also */ - dest = (const struct eth_addr *)ðbroadcast; - /* multicast destination IP address? */ - } else if (ip4_addr_ismulticast(ipaddr)) { - /* Hash IP multicast address to MAC address.*/ - mcastaddr.addr[0] = LL_IP4_MULTICAST_ADDR_0; - mcastaddr.addr[1] = LL_IP4_MULTICAST_ADDR_1; - mcastaddr.addr[2] = LL_IP4_MULTICAST_ADDR_2; - 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 { - netif_addr_idx_t i; - /* outside local network? if so, this can neither be a global broadcast nor - a subnet broadcast. */ - if (!ip4_addr_netcmp(ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) && - !ip4_addr_islinklocal(ipaddr)) { -#if LWIP_AUTOIP - struct ip_hdr *iphdr = LWIP_ALIGNMENT_CAST(struct ip_hdr *, q->payload); - /* 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 (!ip4_addr_islinklocal(&iphdr->src)) -#endif /* LWIP_AUTOIP */ - { -#ifdef LWIP_HOOK_ETHARP_GET_GW - /* For advanced routing, a single default gateway might not be enough, so get - the IP address of the gateway to handle the current destination address. */ - dst_addr = LWIP_HOOK_ETHARP_GET_GW(netif, ipaddr); - if (dst_addr == NULL) -#endif /* LWIP_HOOK_ETHARP_GET_GW */ - { - /* interface has default gateway? */ - if (!ip4_addr_isany_val(*netif_ip4_gw(netif))) { - /* send to hardware address of default gateway IP address */ - dst_addr = netif_ip4_gw(netif); - /* no default gateway available */ - } else { - /* no route to destination error (default gateway missing) */ - return ERR_RTE; - } - } - } - } -#if LWIP_NETIF_HWADDRHINT - if (netif->hints != NULL) { - /* per-pcb cached entry was given */ - netif_addr_idx_t etharp_cached_entry = netif->hints->addr_hint; - if (etharp_cached_entry < ARP_TABLE_SIZE) { -#endif /* LWIP_NETIF_HWADDRHINT */ - if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) && -#if ETHARP_TABLE_MATCH_NETIF - (arp_table[etharp_cached_entry].netif == netif) && -#endif - (ip4_addr_cmp(dst_addr, &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) && -#if ETHARP_TABLE_MATCH_NETIF - (arp_table[i].netif == netif) && -#endif - (ip4_addr_cmp(dst_addr, &arp_table[i].ipaddr))) { - /* found an existing, stable entry */ - ETHARP_SET_ADDRHINT(netif, i); - return etharp_output_to_arp_index(netif, q, i); - } - } - /* no stable entry found, use the (slower) query function: - queue on destination Ethernet address belonging to ipaddr */ - return etharp_query(netif, dst_addr, q); - } - - /* continuation for multicast/broadcast destinations */ - /* obtain source Ethernet address of the given interface */ - /* send packet directly on the link */ - return ethernet_output(netif, q, (struct eth_addr *)(netif->hwaddr), dest, ETHTYPE_IP); -} - -/** - * 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, const ip4_addr_t *ipaddr, struct pbuf *q) -{ - struct eth_addr *srcaddr = (struct eth_addr *)netif->hwaddr; - err_t result = ERR_MEM; - int is_new_entry = 0; - s16_t i_err; - netif_addr_idx_t i; - - /* non-unicast address? */ - if (ip4_addr_isbroadcast(ipaddr, netif) || - ip4_addr_ismulticast(ipaddr) || - ip4_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_err = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD, netif); - - /* could not find or create entry? */ - if (i_err < 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_err; - } - LWIP_ASSERT("type overflow", (size_t)i_err < NETIF_ADDR_IDX_MAX); - i = (netif_addr_idx_t)i_err; - - /* mark a fresh entry as pending (we just sent a request) */ - if (arp_table[i].state == ETHARP_STATE_EMPTY) { - is_new_entry = 1; - arp_table[i].state = ETHARP_STATE_PENDING; - /* record network interface for re-sending arp request in etharp_tmr */ - arp_table[i].netif = netif; - } - - /* { 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 new entry? or an implicit query request? */ - if (is_new_entry || (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_ADDRHINT(netif, i); - /* send the packet */ - result = ethernet_output(netif, q, srcaddr, &(arp_table[i].ethaddr), ETHTYPE_IP); - /* 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 that must be copied, copy the whole chain into a - * new PBUF_RAM. See the definition of PBUF_NEEDS_COPY for details. */ - p = q; - while (p) { - LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); - if (PBUF_NEEDS_COPY(p)) { - copy_needed = 1; - break; - } - p = p->next; - } - if (copy_needed) { - /* copy the whole packet into new pbufs */ - p = pbuf_clone(PBUF_LINK, PBUF_RAM, q); - } 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 ARP_QUEUE_LEN - if (qlen >= ARP_QUEUE_LEN) { - 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(MEMP_ARP_QUEUE, old); - } -#endif - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"U16_F"\n", (void *)q, 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 %"U16_F"\n", (void *)q, (u16_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 %"U16_F"\n", (void *)q, (u16_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 - */ -static err_t -etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, - const struct eth_addr *ethdst_addr, - const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr, - const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr, - const u16_t opcode) -{ - struct pbuf *p; - err_t result = ERR_OK; - struct etharp_hdr *hdr; - - LWIP_ASSERT("netif != NULL", netif != NULL); - - /* allocate a pbuf for the outgoing ARP request packet */ - p = pbuf_alloc(PBUF_LINK, SIZEOF_ETHARP_HDR, 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_HDR)); - - hdr = (struct etharp_hdr *)p->payload; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); - hdr->opcode = lwip_htons(opcode); - - LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!", - (netif->hwaddr_len == ETH_HWADDR_LEN)); - - /* Write the ARP MAC-Addresses */ - SMEMCPY(&hdr->shwaddr, hwsrc_addr, ETH_HWADDR_LEN); - SMEMCPY(&hdr->dhwaddr, hwdst_addr, ETH_HWADDR_LEN); - /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support compilers without - * structure packing. */ - IPADDR_WORDALIGNED_COPY_FROM_IP4_ADDR_T(&hdr->sipaddr, ipsrc_addr); - IPADDR_WORDALIGNED_COPY_FROM_IP4_ADDR_T(&hdr->dipaddr, ipdst_addr); - - hdr->hwtype = PP_HTONS(LWIP_IANA_HWTYPE_ETHERNET); - hdr->proto = PP_HTONS(ETHTYPE_IP); - /* set hwlen and protolen */ - hdr->hwlen = ETH_HWADDR_LEN; - hdr->protolen = sizeof(ip4_addr_t); - - /* send ARP query */ -#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) */ - if (ip4_addr_islinklocal(ipsrc_addr)) { - ethernet_output(netif, p, ethsrc_addr, ðbroadcast, ETHTYPE_ARP); - } else -#endif /* LWIP_AUTOIP */ - { - ethernet_output(netif, p, ethsrc_addr, ethdst_addr, ETHTYPE_ARP); - } - - 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 to a specific eth address. - * Used to send unicast request to refresh the ARP table just before an entry - * times out - * - * @param netif the lwip network interface on which to send the request - * @param ipaddr the IP address for which to ask - * @param hw_dst_addr the ethernet address to send this packet to - * @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 - */ -static err_t -etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr *hw_dst_addr) -{ - return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, hw_dst_addr, - (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif), ðzero, - ipaddr, ARP_REQUEST); -} - -/** - * 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, const ip4_addr_t *ipaddr) -{ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); - return etharp_request_dst(netif, ipaddr, ðbroadcast); -} - -#endif /* LWIP_IPV4 && LWIP_ARP */ diff --git a/core/c/core/ipv4/icmp.c b/core/c/core/ipv4/icmp.c deleted file mode 100755 index fd9054b..0000000 --- a/core/c/core/ipv4/icmp.c +++ /dev/null @@ -1,404 +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_IPV4 && LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/icmp.h" -#include "lwip/inet_chksum.h" -#include "lwip/ip.h" -#include "lwip/def.h" -#include "lwip/stats.h" - -#include - -#ifdef LWIP_HOOK_FILENAME -#include LWIP_HOOK_FILENAME -#endif - -/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be - * used to modify and send a response packet (and to 1 if this is not the case, - * e.g. when link header is stripped off 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 icmp 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; - const struct ip_hdr *iphdr_in; - u16_t hlen; - const ip4_addr_t *src; - - ICMP_STATS_INC(icmp.recv); - MIB2_STATS_INC(mib2.icmpinmsgs); - - iphdr_in = ip4_current_header(); - hlen = IPH_HL_BYTES(iphdr_in); - if (hlen < IP_HLEN) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short IP header (%"S16_F" bytes) received\n", hlen)); - goto lenerr; - } - if (p->len < sizeof(u16_t) * 2) { - 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); - /* if debug is enabled but debug statement below is somehow disabled: */ - LWIP_UNUSED_ARG(code); -#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). */ - MIB2_STATS_INC(mib2.icmpinechoreps); - break; - case ICMP_ECHO: - MIB2_STATS_INC(mib2.icmpinechos); - src = ip4_current_dest_addr(); - /* multicast destination address? */ - if (ip4_addr_ismulticast(ip4_current_dest_addr())) { -#if LWIP_MULTICAST_PING - /* For multicast, use address of receiving interface as source address */ - src = netif_ip4_addr(inp); -#else /* LWIP_MULTICAST_PING */ - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast pings\n")); - goto icmperr; -#endif /* LWIP_MULTICAST_PING */ - } - /* broadcast destination address? */ - if (ip4_addr_isbroadcast(ip4_current_dest_addr(), ip_current_netif())) { -#if LWIP_BROADCAST_PING - /* For broadcast, use address of receiving interface as source address */ - src = netif_ip4_addr(inp); -#else /* LWIP_BROADCAST_PING */ - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to broadcast pings\n")); - goto icmperr; -#endif /* LWIP_BROADCAST_PING */ - } - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); - if (p->tot_len < sizeof(struct icmp_echo_hdr)) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); - goto lenerr; - } -#if CHECKSUM_CHECK_ICMP - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP) { - if (inet_chksum_pbuf(p) != 0) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); - pbuf_free(p); - ICMP_STATS_INC(icmp.chkerr); - MIB2_STATS_INC(mib2.icmpinerrors); - return; - } - } -#endif -#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN - if (pbuf_add_header(p, hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN)) { - /* p is not big enough to contain link headers - * allocate a new one and copy p into it - */ - struct pbuf *r; - u16_t alloc_len = (u16_t)(p->tot_len + hlen); - if (alloc_len < p->tot_len) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed (tot_len overflow)\n")); - goto icmperr; - } - /* allocate new packet buffer with space for link headers */ - r = pbuf_alloc(PBUF_LINK, alloc_len, PBUF_RAM); - if (r == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); - goto icmperr; - } - if (r->len < hlen + sizeof(struct icmp_echo_hdr)) { - LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("first pbuf cannot hold the ICMP header")); - pbuf_free(r); - goto icmperr; - } - /* copy the ip header */ - MEMCPY(r->payload, iphdr_in, hlen); - /* switch r->payload back to icmp header (cannot fail) */ - if (pbuf_remove_header(r, hlen)) { - LWIP_ASSERT("icmp_input: moving r->payload to icmp header failed\n", 0); - pbuf_free(r); - goto icmperr; - } - /* copy the rest of the packet without ip header */ - if (pbuf_copy(r, p) != ERR_OK) { - LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("icmp_input: copying to new pbuf failed")); - pbuf_free(r); - goto icmperr; - } - /* free the original p */ - pbuf_free(p); - /* we now have an identical copy of p that has room for link headers */ - p = r; - } else { - /* restore p->payload to point to icmp header (cannot fail) */ - if (pbuf_remove_header(p, hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN)) { - LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); - goto icmperr; - } - } -#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; - if (pbuf_add_header(p, hlen)) { - LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Can't move over header in packet")); - } else { - err_t ret; - struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; - ip4_addr_copy(iphdr->src, *src); - ip4_addr_copy(iphdr->dest, *ip4_current_src_addr()); - ICMPH_TYPE_SET(iecho, ICMP_ER); -#if CHECKSUM_GEN_ICMP - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP) { - /* adjust the checksum */ - if (iecho->chksum > PP_HTONS(0xffffU - (ICMP_ECHO << 8))) { - iecho->chksum = (u16_t)(iecho->chksum + PP_HTONS((u16_t)(ICMP_ECHO << 8)) + 1); - } else { - iecho->chksum = (u16_t)(iecho->chksum + PP_HTONS(ICMP_ECHO << 8)); - } - } -#if LWIP_CHECKSUM_CTRL_PER_NETIF - else { - iecho->chksum = 0; - } -#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ -#else /* CHECKSUM_GEN_ICMP */ - iecho->chksum = 0; -#endif /* CHECKSUM_GEN_ICMP */ - - /* Set the correct TTL and recalculate the header checksum. */ - IPH_TTL_SET(iphdr, ICMP_TTL); - IPH_CHKSUM_SET(iphdr, 0); -#if CHECKSUM_GEN_IP - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_IP) { - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, hlen)); - } -#endif /* CHECKSUM_GEN_IP */ - - ICMP_STATS_INC(icmp.xmit); - /* increase number of messages attempted to send */ - MIB2_STATS_INC(mib2.icmpoutmsgs); - /* increase number of echo replies attempted to send */ - MIB2_STATS_INC(mib2.icmpoutechoreps); - - /* send an ICMP packet */ - ret = ip4_output_if(p, src, LWIP_IP_HDRINCL, - ICMP_TTL, 0, IP_PROTO_ICMP, inp); - if (ret != ERR_OK) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %s\n", lwip_strerr(ret))); - } - } - break; - default: - if (type == ICMP_DUR) { - MIB2_STATS_INC(mib2.icmpindestunreachs); - } else if (type == ICMP_TE) { - MIB2_STATS_INC(mib2.icmpintimeexcds); - } else if (type == ICMP_PP) { - MIB2_STATS_INC(mib2.icmpinparmprobs); - } else if (type == ICMP_SQ) { - MIB2_STATS_INC(mib2.icmpinsrcquenchs); - } else if (type == ICMP_RD) { - MIB2_STATS_INC(mib2.icmpinredirects); - } else if (type == ICMP_TS) { - MIB2_STATS_INC(mib2.icmpintimestamps); - } else if (type == ICMP_TSR) { - MIB2_STATS_INC(mib2.icmpintimestampreps); - } else if (type == ICMP_AM) { - MIB2_STATS_INC(mib2.icmpinaddrmasks); - } else if (type == ICMP_AMR) { - MIB2_STATS_INC(mib2.icmpinaddrmaskreps); - } - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", - (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); - MIB2_STATS_INC(mib2.icmpinerrors); - return; -#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING -icmperr: - pbuf_free(p); - ICMP_STATS_INC(icmp.err); - MIB2_STATS_INC(mib2.icmpinerrors); - return; -#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ -} - -/** - * 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) -{ - MIB2_STATS_INC(mib2.icmpoutdestunreachs); - 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) -{ - MIB2_STATS_INC(mib2.icmpouttimeexcds); - icmp_send_response(p, ICMP_TE, t); -} - -#endif /* IP_FORWARD || IP_REASSEMBLY */ - -/** - * Send an icmp packet in response to an incoming packet. - * - * @param p the input packet for which the 'unreachable' should be sent, - * p->payload pointing to the IP header - * @param type Type of the ICMP header - * @param code Code of the ICMP header - */ -static void -icmp_send_response(struct pbuf *p, u8_t type, u8_t code) -{ - struct pbuf *q; - struct ip_hdr *iphdr; - /* we can use the echo header here */ - struct icmp_echo_hdr *icmphdr; - ip4_addr_t iphdr_src; - struct netif *netif; - - /* increase number of messages attempted to send */ - MIB2_STATS_INC(mib2.icmpoutmsgs); - - /* ICMP header + IP header + 8 bytes of data */ - q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, - PBUF_RAM); - if (q == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); - MIB2_STATS_INC(mib2.icmpouterrors); - return; - } - LWIP_ASSERT("check that first pbuf can hold icmp message", - (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); - - iphdr = (struct ip_hdr *)p->payload; - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); - ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->src); - LWIP_DEBUGF(ICMP_DEBUG, (" to ")); - ip4_addr_debug_print_val(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; - - /* copy fields from original packet */ - SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, - IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); - - ip4_addr_copy(iphdr_src, iphdr->src); -#ifdef LWIP_HOOK_IP4_ROUTE_SRC - { - ip4_addr_t iphdr_dst; - ip4_addr_copy(iphdr_dst, iphdr->dest); - netif = ip4_route_src(&iphdr_dst, &iphdr_src); - } -#else - netif = ip4_route(&iphdr_src); -#endif - if (netif != NULL) { - /* calculate checksum */ - icmphdr->chksum = 0; -#if CHECKSUM_GEN_ICMP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP) { - icmphdr->chksum = inet_chksum(icmphdr, q->len); - } -#endif - ICMP_STATS_INC(icmp.xmit); - ip4_output_if(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP, netif); - } - pbuf_free(q); -} - -#endif /* LWIP_IPV4 && LWIP_ICMP */ diff --git a/core/c/core/ipv4/igmp.c b/core/c/core/ipv4/igmp.c deleted file mode 100755 index 61f45d9..0000000 --- a/core/c/core/ipv4/igmp.c +++ /dev/null @@ -1,801 +0,0 @@ -/** - * @file - * IGMP - Internet Group Management Protocol - * - * @defgroup igmp IGMP - * @ingroup ip4 - * To be called from TCPIP thread - */ - -/* - * 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_IPV4 && 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/stats.h" -#include "lwip/prot/igmp.h" - -#include - -static struct igmp_group *igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr); -static err_t igmp_remove_group(struct netif *netif, struct igmp_group *group); -static void igmp_timeout(struct netif *netif, struct igmp_group *group); -static void igmp_start_timer(struct igmp_group *group, u8_t max_time); -static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp); -static err_t igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif); -static void igmp_send(struct netif *netif, struct igmp_group *group, u8_t type); - -static ip4_addr_t allsystems; -static ip4_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); -} - -/** - * 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", (void *)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 ")); - ip4_addr_debug_print_val(IGMP_DEBUG, allsystems); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void *)netif)); - netif->igmp_mac_filter(netif, &allsystems, NETIF_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 = netif_igmp_data(netif); - - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, NULL); - - while (group != NULL) { - struct igmp_group *next = group->next; /* avoid use-after-free below */ - - /* disable the group at the MAC level */ - if (netif->igmp_mac_filter != NULL) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); - ip4_addr_debug_print_val(IGMP_DEBUG, group->group_address); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void *)netif)); - netif->igmp_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER); - } - - /* free group */ - memp_free(MEMP_IGMP_GROUP, 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 = netif_igmp_data(netif); - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", (void *)netif)); - - /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */ - if (group != NULL) { - group = group->next; - } - - while (group != NULL) { - igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); - group = group->next; - } -} - -/** - * Search for a group in the netif's 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, const ip4_addr_t *addr) -{ - struct igmp_group *group = netif_igmp_data(ifp); - - while (group != NULL) { - if (ip4_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. - */ -static struct igmp_group * -igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr) -{ - struct igmp_group *group; - struct igmp_group *list_head = netif_igmp_data(ifp); - - /* 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) { - ip4_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; - - /* Ensure allsystems group is always first in list */ - if (list_head == NULL) { - /* this is the first entry in linked list */ - LWIP_ASSERT("igmp_lookup_group: first group must be allsystems", - (ip4_addr_cmp(addr, &allsystems) != 0)); - group->next = NULL; - netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, group); - } else { - /* append _after_ first entry */ - LWIP_ASSERT("igmp_lookup_group: all except first group must not be allsystems", - (ip4_addr_cmp(addr, &allsystems) == 0)); - group->next = list_head->next; - list_head->next = group; - } - } - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group ? "" : "impossible to "))); - ip4_addr_debug_print(IGMP_DEBUG, addr); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void *)ifp)); - - return group; -} - -/** - * Remove a group from netif's igmp group list, but don't free it yet - * - * @param group the group to remove from the netif's igmp group list - * @return ERR_OK if group was removed from the list, an err_t otherwise - */ -static err_t -igmp_remove_group(struct netif *netif, struct igmp_group *group) -{ - err_t err = ERR_OK; - struct igmp_group *tmp_group; - - /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */ - for (tmp_group = netif_igmp_data(netif); tmp_group != NULL; tmp_group = tmp_group->next) { - if (tmp_group->next == group) { - tmp_group->next = group->next; - break; - } - } - /* Group not found in netif's igmp group list */ - if (tmp_group == NULL) { - err = ERR_ARG; - } - - return err; -} - -/** - * Called from ip_input() if a new IGMP packet is received. - * - * @param p received igmp packet, p->payload pointing to the igmp header - * @param inp network interface on which the packet was received - * @param dest destination ip address of the igmp packet - */ -void -igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest) -{ - 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 */ - if (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 ")); - ip4_addr_debug_print_val(IGMP_DEBUG, ip4_current_header()->src); - LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); - ip4_addr_debug_print_val(IGMP_DEBUG, ip4_current_header()->dest); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void *)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 ((ip4_addr_cmp(dest, &allsystems)) && ip4_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 = netif_igmp_data(inp); - - /* Do not send messages on the all systems group address! */ - /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */ - if (groupref != NULL) { - groupref = groupref->next; - } - - while (groupref) { - igmp_delaying_member(groupref, igmp->igmp_maxresp); - groupref = groupref->next; - } - } else { - /* IGMP_MEMB_QUERY to a specific group ? */ - if (!ip4_addr_isany(&igmp->igmp_group_address)) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); - ip4_addr_debug_print_val(IGMP_DEBUG, igmp->igmp_group_address); - if (ip4_addr_cmp(dest, &allsystems)) { - ip4_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 */ - ip4_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, (void *)&group, (void *)inp)); - IGMP_STATS_INC(igmp.proterr); - break; - } - - pbuf_free(p); - return; -} - -/** - * @ingroup igmp - * 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(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr) -{ - err_t err = ERR_VAL; /* no matching interface */ - struct netif *netif; - - LWIP_ASSERT_CORE_LOCKED(); - - /* make sure it is multicast address */ - LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); - LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); - - /* loop through netif's */ - NETIF_FOREACH(netif) { - /* Should we join this interface ? */ - if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) { - err = igmp_joingroup_netif(netif, groupaddr); - if (err != ERR_OK) { - /* Return an error even if some network interfaces are joined */ - /** @todo undo any other netif already joined */ - return err; - } - } - } - - return err; -} - -/** - * @ingroup igmp - * Join a group on one network interface. - * - * @param netif 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, an err_t otherwise - */ -err_t -igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr) -{ - struct igmp_group *group; - - LWIP_ASSERT_CORE_LOCKED(); - - /* make sure it is multicast address */ - LWIP_ERROR("igmp_joingroup_netif: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); - LWIP_ERROR("igmp_joingroup_netif: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); - - /* make sure it is an igmp-enabled netif */ - LWIP_ERROR("igmp_joingroup_netif: attempt to join on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;); - - /* 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_netif: join to group not in state IGMP_GROUP_NON_MEMBER\n")); - } else { - /* OK - it was new group */ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: join to new group: ")); - ip4_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_netif: igmp_mac_filter(ADD ")); - ip4_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void *)netif)); - netif->igmp_mac_filter(netif, groupaddr, NETIF_ADD_MAC_FILTER); - } - - IGMP_STATS_INC(igmp.tx_join); - igmp_send(netif, 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 */ - return ERR_OK; - } else { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: Not enough memory to join to group\n")); - return ERR_MEM; - } -} - -/** - * @ingroup igmp - * 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(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr) -{ - err_t err = ERR_VAL; /* no matching interface */ - struct netif *netif; - - LWIP_ASSERT_CORE_LOCKED(); - - /* make sure it is multicast address */ - LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); - LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); - - /* loop through netif's */ - NETIF_FOREACH(netif) { - /* Should we leave this interface ? */ - if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) { - err_t res = igmp_leavegroup_netif(netif, groupaddr); - if (err != ERR_OK) { - /* Store this result if we have not yet gotten a success */ - err = res; - } - } - } - - return err; -} - -/** - * @ingroup igmp - * Leave a group on one network interface. - * - * @param netif 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, an err_t otherwise - */ -err_t -igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr) -{ - struct igmp_group *group; - - LWIP_ASSERT_CORE_LOCKED(); - - /* make sure it is multicast address */ - LWIP_ERROR("igmp_leavegroup_netif: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); - LWIP_ERROR("igmp_leavegroup_netif: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); - - /* make sure it is an igmp-enabled netif */ - LWIP_ERROR("igmp_leavegroup_netif: attempt to leave on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;); - - /* 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_netif: Leaving group: ")); - ip4_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, ("\n")); - - /* If there is no other use of the group */ - if (group->use <= 1) { - /* Remove the group from the list */ - igmp_remove_group(netif, group); - - /* If we are the last reporter for this group */ - if (group->last_reporter_flag) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: sending leaving group\n")); - IGMP_STATS_INC(igmp.tx_leave); - igmp_send(netif, group, IGMP_LEAVE_GROUP); - } - - /* Disable the group at the MAC level */ - if (netif->igmp_mac_filter != NULL) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: igmp_mac_filter(DEL ")); - ip4_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void *)netif)); - netif->igmp_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER); - } - - /* Free group struct */ - memp_free(MEMP_IGMP_GROUP, group); - } else { - /* Decrement group use */ - group->use--; - } - return ERR_OK; - } else { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: not member of group\n")); - return ERR_VAL; - } -} - -/** - * 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 netif *netif; - - NETIF_FOREACH(netif) { - struct igmp_group *group = netif_igmp_data(netif); - - while (group != NULL) { - if (group->timer > 0) { - group->timer--; - if (group->timer == 0) { - igmp_timeout(netif, 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 netif *netif, struct igmp_group *group) -{ - /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group - (unless it is the allsystems group) */ - if ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && - (!(ip4_addr_cmp(&(group->group_address), &allsystems)))) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); - ip4_addr_debug_print_val(IGMP_DEBUG, group->group_address); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void *)netif)); - - group->group_state = IGMP_GROUP_IDLE_MEMBER; - - IGMP_STATS_INC(igmp.tx_report); - igmp_send(netif, 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) -{ -#ifdef LWIP_RAND - group->timer = (u16_t)(max_time > 2 ? (LWIP_RAND() % max_time) : 1); -#else /* LWIP_RAND */ - /* ATTENTION: use this only if absolutely necessary! */ - group->timer = max_time / 2; -#endif /* LWIP_RAND */ - - if (group->timer == 0) { - group->timer = 1; - } -} - -/** - * 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 == LWIP_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 == IP4_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 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, const ip4_addr_t *src, const ip4_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 ip4_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 netif *netif, struct igmp_group *group, u8_t type) -{ - struct pbuf *p = NULL; - struct igmp_msg *igmp = NULL; - ip4_addr_t src = *IP4_ADDR_ANY4; - ip4_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))); - ip4_addr_copy(src, *netif_ip4_addr(netif)); - - if (type == IGMP_V2_MEMB_REPORT) { - dest = &(group->group_address); - ip4_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; - ip4_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, 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_IPV4 && LWIP_IGMP */ diff --git a/core/c/core/ipv4/ip4.c b/core/c/core/ipv4/ip4.c deleted file mode 100755 index e638eb8..0000000 --- a/core/c/core/ipv4/ip4.c +++ /dev/null @@ -1,1145 +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" - -#if LWIP_IPV4 - -#include "lwip/ip.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/ip4_frag.h" -#include "lwip/inet_chksum.h" -#include "lwip/netif.h" -#include "lwip/icmp.h" -#include "lwip/igmp.h" -#include "lwip/priv/raw_priv.h" -#include "lwip/udp.h" -#include "lwip/priv/tcp_priv.h" -#include "lwip/autoip.h" -#include "lwip/stats.h" -#include "lwip/prot/iana.h" - -#include - -#ifdef LWIP_HOOK_FILENAME -#include LWIP_HOOK_FILENAME -#endif - -/** 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 -#if LWIP_CHECKSUM_CTRL_PER_NETIF -#define LWIP_INLINE_IP_CHKSUM 0 -#else /* LWIP_CHECKSUM_CTRL_PER_NETIF */ -#define LWIP_INLINE_IP_CHKSUM 1 -#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ -#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(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(LWIP_IANA_PORT_DHCP_CLIENT)) \ - || (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(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(LWIP_IANA_PORT_DHCP_CLIENT)) -#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ - -#else /* LWIP_DHCP */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0 -#endif /* LWIP_DHCP */ - -/** The IP header ID of the next outgoing IP packet */ -static u16_t ip_id; - -#if LWIP_MULTICAST_TX_OPTIONS -/** The default netif used for multicast */ -static struct netif *ip4_default_multicast_netif; - -/** - * @ingroup ip4 - * Set a default netif for IPv4 multicast. */ -void -ip4_set_default_multicast_netif(struct netif *default_multicast_netif) -{ - ip4_default_multicast_netif = default_multicast_netif; -} -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - -#ifdef LWIP_HOOK_IP4_ROUTE_SRC -/** - * Source based IPv4 routing must be fully implemented in - * LWIP_HOOK_IP4_ROUTE_SRC(). This function only provides the parameters. - */ -struct netif * -ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest) -{ - if (src != NULL) { - /* when src==NULL, the hook is called from ip4_route(dest) */ - struct netif *netif = LWIP_HOOK_IP4_ROUTE_SRC(src, dest); - if (netif != NULL) { - return netif; - } - } - return ip4_route(dest); -} -#endif /* LWIP_HOOK_IP4_ROUTE_SRC */ - -/** - * 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 * -ip4_route(const ip4_addr_t *dest) -{ -#if TUN2SOCKS - // go-tun2socks logic - // no routing and just use the default netif, netif_list[0], i.e., the loopif - // enable loopif by setting LWIP_HAVE_LOOPIF = 1 in lwipopts.h - return netif_list; -#endif /* TUN2SOCKS */ - -#if !LWIP_SINGLE_NETIF - struct netif *netif; - - LWIP_ASSERT_CORE_LOCKED(); - -#if LWIP_MULTICAST_TX_OPTIONS - /* Use administratively selected interface for multicast by default */ - if (ip4_addr_ismulticast(dest) && ip4_default_multicast_netif) { - return ip4_default_multicast_netif; - } -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - - /* bug #54569: in case LWIP_SINGLE_NETIF=1 and LWIP_DEBUGF() disabled, the following loop is optimized away */ - LWIP_UNUSED_ARG(dest); - - /* iterate through netifs */ - NETIF_FOREACH(netif) { - /* is the netif up, does it have a link and a valid address? */ - if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) { - /* network mask matches? */ - if (ip4_addr_netcmp(dest, netif_ip4_addr(netif), netif_ip4_netmask(netif))) { - /* return netif on which to forward IP packet */ - return netif; - } - /* gateway matches on a non broadcast interface? (i.e. peer in a point to point interface) */ - if (((netif->flags & NETIF_FLAG_BROADCAST) == 0) && ip4_addr_cmp(dest, netif_ip4_gw(netif))) { - /* return netif on which to forward IP packet */ - return netif; - } - } - } - -#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF - /* loopif is disabled, looopback traffic is passed through any netif */ - if (ip4_addr_isloopback(dest)) { - /* don't check for link on loopback traffic */ - if (netif_default != NULL && netif_is_up(netif_default)) { - return netif_default; - } - /* default netif is not up, just use any netif for loopback traffic */ - NETIF_FOREACH(netif) { - if (netif_is_up(netif)) { - return netif; - } - } - return NULL; - } -#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */ - -#ifdef LWIP_HOOK_IP4_ROUTE_SRC - netif = LWIP_HOOK_IP4_ROUTE_SRC(NULL, dest); - if (netif != NULL) { - return netif; - } -#elif defined(LWIP_HOOK_IP4_ROUTE) - netif = LWIP_HOOK_IP4_ROUTE(dest); - if (netif != NULL) { - return netif; - } -#endif -#endif /* !LWIP_SINGLE_NETIF */ - - if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default) || - ip4_addr_isany_val(*netif_ip4_addr(netif_default)) || ip4_addr_isloopback(dest)) { - /* No matching netif found and default netif is not usable. - If this is not good enough for you, use LWIP_HOOK_IP4_ROUTE() */ - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_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); - MIB2_STATS_INC(mib2.ipoutnoroutes); - return NULL; - } - - return netif_default; -} - -#if IP_FORWARD -/** - * Determine whether an IP address is in a reserved set of addresses - * that may not be forwarded, or whether datagrams to that destination - * may be forwarded. - * @param p the packet to forward - * @return 1: can forward 0: discard - */ -static int -ip4_canforward(struct pbuf *p) -{ - u32_t addr = lwip_htonl(ip4_addr_get_u32(ip4_current_dest_addr())); - -#ifdef LWIP_HOOK_IP4_CANFORWARD - int ret = LWIP_HOOK_IP4_CANFORWARD(p, addr); - if (ret >= 0) { - return ret; - } -#endif /* LWIP_HOOK_IP4_CANFORWARD */ - - if (p->flags & PBUF_FLAG_LLBCAST) { - /* don't route link-layer broadcasts */ - return 0; - } - if ((p->flags & PBUF_FLAG_LLMCAST) || IP_MULTICAST(addr)) { - /* don't route link-layer multicasts (use LWIP_HOOK_IP4_CANFORWARD instead) */ - return 0; - } - if (IP_EXPERIMENTAL(addr)) { - return 0; - } - if (IP_CLASSA(addr)) { - u32_t net = addr & IP_CLASSA_NET; - if ((net == 0) || (net == ((u32_t)IP_LOOPBACKNET << IP_CLASSA_NSHIFT))) { - /* don't route loopback packets */ - return 0; - } - } - return 1; -} - -/** - * 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 -ip4_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) -{ - struct netif *netif; - - PERF_START; - LWIP_UNUSED_ARG(inp); - - if (!ip4_canforward(p)) { - goto return_noroute; - } - - /* RFC3927 2.7: do not forward link-local addresses */ - if (ip4_addr_islinklocal(ip4_current_dest_addr())) { - LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()), - ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr()))); - goto return_noroute; - } - - /* Find network interface where to forward this IP packet to. */ - netif = ip4_route_src(ip4_current_src_addr(), ip4_current_dest_addr()); - if (netif == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n", - ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()), - ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr()))); - /* @todo: send ICMP_DUR_NET? */ - goto return_noroute; - } -#if !IP_FORWARD_ALLOW_TX_ON_RX_NETIF - /* Do not forward packets onto the same network interface on which - * they arrived. */ - if (netif == inp) { - LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: not bouncing packets back on incoming interface.\n")); - goto return_noroute; - } -#endif /* IP_FORWARD_ALLOW_TX_ON_RX_NETIF */ - - /* decrement TTL */ - IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); - /* send ICMP if TTL == 0 */ - if (IPH_TTL(iphdr) == 0) { - MIB2_STATS_INC(mib2.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(0xffffU - 0x100)) { - IPH_CHKSUM_SET(iphdr, (u16_t)(IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1)); - } else { - IPH_CHKSUM_SET(iphdr, (u16_t)(IPH_CHKSUM(iphdr) + PP_HTONS(0x100))); - } - - LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()), - ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr()))); - - IP_STATS_INC(ip.fw); - MIB2_STATS_INC(mib2.ipforwdatagrams); - IP_STATS_INC(ip.xmit); - - PERF_STOP("ip4_forward"); - /* don't fragment if interface has mtu set to 0 [loopif] */ - if (netif->mtu && (p->tot_len > netif->mtu)) { - if ((IPH_OFFSET(iphdr) & PP_NTOHS(IP_DF)) == 0) { -#if IP_FRAG - ip4_frag(p, netif, ip4_current_dest_addr()); -#else /* IP_FRAG */ - /* @todo: send ICMP Destination Unreachable code 13 "Communication administratively prohibited"? */ -#endif /* IP_FRAG */ - } else { -#if LWIP_ICMP - /* send ICMP Destination Unreachable code 4: "Fragmentation Needed and DF Set" */ - icmp_dest_unreach(p, ICMP_DUR_FRAG); -#endif /* LWIP_ICMP */ - } - return; - } - /* transmit pbuf on chosen interface */ - netif->output(netif, p, ip4_current_dest_addr()); - return; -return_noroute: - MIB2_STATS_INC(mib2.ipoutnoroutes); -} -#endif /* IP_FORWARD */ - -/** Return true if the current input packet should be accepted on this netif */ -static int -ip4_input_accept(struct netif *netif) -{ -#if TUN2SOCKS - // go-tun2socks logic - // all packets are accepted by the first one, and it should be the loopif - return 1; -#endif /* TUN2SOCKS */ - - 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(ip4_current_dest_addr()), ip4_addr_get_u32(netif_ip4_addr(netif)), - ip4_addr_get_u32(ip4_current_dest_addr()) & ip4_addr_get_u32(netif_ip4_netmask(netif)), - ip4_addr_get_u32(netif_ip4_addr(netif)) & ip4_addr_get_u32(netif_ip4_netmask(netif)), - ip4_addr_get_u32(ip4_current_dest_addr()) & ~ip4_addr_get_u32(netif_ip4_netmask(netif)))); - - /* interface is up and configured? */ - if ((netif_is_up(netif)) && (!ip4_addr_isany_val(*netif_ip4_addr(netif)))) { - /* unicast to this interface address? */ - if (ip4_addr_cmp(ip4_current_dest_addr(), netif_ip4_addr(netif)) || - /* or broadcast on this interface network address? */ - ip4_addr_isbroadcast(ip4_current_dest_addr(), netif) -#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF - || (ip4_addr_get_u32(ip4_current_dest_addr()) == PP_HTONL(IPADDR_LOOPBACK)) -#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */ - ) { - LWIP_DEBUGF(IP_DEBUG, ("ip4_input: packet accepted on interface %c%c\n", - netif->name[0], netif->name[1])); - /* accept on this netif */ - return 1; - } -#if LWIP_AUTOIP - /* connections to link-local addresses must persist after changing - the netif's address (RFC3927 ch. 1.9) */ - if (autoip_accept_packet(netif, ip4_current_dest_addr())) { - LWIP_DEBUGF(IP_DEBUG, ("ip4_input: LLA packet accepted on interface %c%c\n", - netif->name[0], netif->name[1])); - /* accept on this netif */ - return 1; - } -#endif /* LWIP_AUTOIP */ - } - return 0; -} - -/** - * 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 -ip4_input(struct pbuf *p, struct netif *inp) -{ - const struct ip_hdr *iphdr; - struct netif *netif; - u16_t iphdr_hlen; - u16_t iphdr_len; -#if IP_ACCEPT_LINK_LAYER_ADDRESSING || LWIP_IGMP - int check_ip_src = 1; -#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING || LWIP_IGMP */ -#if LWIP_RAW - raw_input_state_t raw_status; -#endif /* LWIP_RAW */ - - LWIP_ASSERT_CORE_LOCKED(); - - IP_STATS_INC(ip.recv); - MIB2_STATS_INC(mib2.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", (u16_t)IPH_V(iphdr))); - ip4_debug_print(p); - pbuf_free(p); - IP_STATS_INC(ip.err); - IP_STATS_INC(ip.drop); - MIB2_STATS_INC(mib2.ipinhdrerrors); - return ERR_OK; - } - -#ifdef LWIP_HOOK_IP4_INPUT - if (LWIP_HOOK_IP4_INPUT(p, inp)) { - /* the packet has been eaten */ - return ERR_OK; - } -#endif - - /* obtain IP header length in bytes */ - iphdr_hlen = IPH_HL_BYTES(iphdr); - /* obtain ip length in bytes */ - iphdr_len = lwip_ntohs(IPH_LEN(iphdr)); - - /* Trim pbuf. This is especially required for packets < 60 bytes. */ - if (iphdr_len < p->tot_len) { - pbuf_realloc(p, iphdr_len); - } - - /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ - if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len) || (iphdr_hlen < IP_HLEN)) { - if (iphdr_hlen < IP_HLEN) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("ip4_input: short IP header (%"U16_F" bytes) received, IP packet dropped\n", iphdr_hlen)); - } - 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); - MIB2_STATS_INC(mib2.ipindiscards); - return ERR_OK; - } - - /* verify checksum */ -#if CHECKSUM_CHECK_IP - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_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))); - ip4_debug_print(p); - pbuf_free(p); - IP_STATS_INC(ip.chkerr); - IP_STATS_INC(ip.drop); - MIB2_STATS_INC(mib2.ipinhdrerrors); - return ERR_OK; - } - } -#endif - - /* copy IP addresses to aligned ip_addr_t */ - ip_addr_copy_from_ip4(ip_data.current_iphdr_dest, iphdr->dest); - ip_addr_copy_from_ip4(ip_data.current_iphdr_src, iphdr->src); - - /* match packet against an interface, i.e. is this packet for us? */ - if (ip4_addr_ismulticast(ip4_current_dest_addr())) { -#if LWIP_IGMP - if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ip4_current_dest_addr()))) { - /* IGMP snooping switches need 0.0.0.0 to be allowed as source address (RFC 4541) */ - ip4_addr_t allsystems; - IP4_ADDR(&allsystems, 224, 0, 0, 1); - if (ip4_addr_cmp(ip4_current_dest_addr(), &allsystems) && - ip4_addr_isany(ip4_current_src_addr())) { - check_ip_src = 0; - } - netif = inp; - } else { - netif = NULL; - } -#else /* LWIP_IGMP */ - if ((netif_is_up(inp)) && (!ip4_addr_isany_val(*netif_ip4_addr(inp)))) { - netif = inp; - } else { - netif = NULL; - } -#endif /* LWIP_IGMP */ - } else { - /* start trying with inp. if that's not acceptable, start walking the - list of configured netifs. */ - if (ip4_input_accept(inp)) { - netif = inp; - } else { - netif = NULL; -#if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF - /* Packets sent to the loopback address must not be accepted on an - * interface that does not have the loopback address assigned to it, - * unless a non-loopback interface is used for loopback traffic. */ - if (!ip4_addr_isloopback(ip4_current_dest_addr())) -#endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */ - { -#if !LWIP_SINGLE_NETIF - NETIF_FOREACH(netif) { - if (netif == inp) { - /* we checked that before already */ - continue; - } - if (ip4_input_accept(netif)) { - break; - } - } -#endif /* !LWIP_SINGLE_NETIF */ - } - } - } - -#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) { - const struct udp_hdr *udphdr = (const struct udp_hdr *)((const u8_t *)iphdr + iphdr_hlen); - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: UDP packet to DHCP client port %"U16_F"\n", - lwip_ntohs(udphdr->dest))); - if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_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 LWIP_IGMP || IP_ACCEPT_LINK_LAYER_ADDRESSING - if (check_ip_src -#if IP_ACCEPT_LINK_LAYER_ADDRESSING - /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */ - && !ip4_addr_isany_val(*ip4_current_src_addr()) -#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ - ) -#endif /* LWIP_IGMP || IP_ACCEPT_LINK_LAYER_ADDRESSING */ - { - if ((ip4_addr_isbroadcast(ip4_current_src_addr(), inp)) || - (ip4_addr_ismulticast(ip4_current_src_addr()))) { - /* packet source is not valid */ - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip4_input: packet source is not valid.\n")); - /* free (drop) packet pbufs */ - pbuf_free(p); - IP_STATS_INC(ip.drop); - MIB2_STATS_INC(mib2.ipinaddrerrors); - MIB2_STATS_INC(mib2.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, ("ip4_input: packet not for us.\n")); -#if IP_FORWARD - /* non-broadcast packet? */ - if (!ip4_addr_isbroadcast(ip4_current_dest_addr(), inp)) { - /* try to forward IP packet on (other) interfaces */ - ip4_forward(p, (struct ip_hdr *)p->payload, inp); - } else -#endif /* IP_FORWARD */ - { - IP_STATS_INC(ip.drop); - MIB2_STATS_INC(mib2.ipinaddrerrors); - MIB2_STATS_INC(mib2.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 ip4_reass()\n", - lwip_ntohs(IPH_ID(iphdr)), p->tot_len, lwip_ntohs(IPH_LEN(iphdr)), (u16_t)!!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (u16_t)((lwip_ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK) * 8))); - /* reassemble the packet*/ - p = ip4_reass(p); - /* packet not fully reassembled yet? */ - if (p == NULL) { - return ERR_OK; - } - iphdr = (const 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", - lwip_ntohs(IPH_OFFSET(iphdr)))); - IP_STATS_INC(ip.opterr); - IP_STATS_INC(ip.drop); - /* unsupported protocol feature */ - MIB2_STATS_INC(mib2.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 */ - MIB2_STATS_INC(mib2.ipinunknownprotos); - return ERR_OK; - } -#endif /* IP_OPTIONS_ALLOWED == 0 */ - - /* send to upper layers */ - LWIP_DEBUGF(IP_DEBUG, ("ip4_input: \n")); - ip4_debug_print(p); - LWIP_DEBUGF(IP_DEBUG, ("ip4_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); - - ip_data.current_netif = netif; - ip_data.current_input_netif = inp; - ip_data.current_ip4_header = iphdr; - ip_data.current_ip_header_tot_len = IPH_HL_BYTES(iphdr); - -#if LWIP_RAW - /* raw input did not eat the packet? */ - raw_status = raw_input(p, inp); - if (raw_status != RAW_INPUT_EATEN) -#endif /* LWIP_RAW */ - { - pbuf_remove_header(p, iphdr_hlen); /* Move to payload, no check necessary. */ - - switch (IPH_PROTO(iphdr)) { -#if LWIP_UDP - case IP_PROTO_UDP: -#if LWIP_UDPLITE - case IP_PROTO_UDPLITE: -#endif /* LWIP_UDPLITE */ - MIB2_STATS_INC(mib2.ipindelivers); - udp_input(p, inp); - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case IP_PROTO_TCP: - MIB2_STATS_INC(mib2.ipindelivers); - tcp_input(p, inp); - break; -#endif /* LWIP_TCP */ -#if LWIP_ICMP - case IP_PROTO_ICMP: - MIB2_STATS_INC(mib2.ipindelivers); - icmp_input(p, inp); - break; -#endif /* LWIP_ICMP */ -#if LWIP_IGMP - case IP_PROTO_IGMP: - igmp_input(p, inp, ip4_current_dest_addr()); - break; -#endif /* LWIP_IGMP */ - default: -#if LWIP_RAW - if (raw_status == RAW_INPUT_DELIVERED) { - MIB2_STATS_INC(mib2.ipindelivers); - } else -#endif /* LWIP_RAW */ - { -#if LWIP_ICMP - /* send ICMP destination protocol unreachable unless is was a broadcast */ - if (!ip4_addr_isbroadcast(ip4_current_dest_addr(), netif) && - !ip4_addr_ismulticast(ip4_current_dest_addr())) { - pbuf_header_force(p, (s16_t)iphdr_hlen); /* Move to ip header, no check necessary. */ - icmp_dest_unreach(p, ICMP_DUR_PROTO); - } -#endif /* LWIP_ICMP */ - - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", (u16_t)IPH_PROTO(iphdr))); - - IP_STATS_INC(ip.proterr); - IP_STATS_INC(ip.drop); - MIB2_STATS_INC(mib2.ipinunknownprotos); - } - pbuf_free(p); - break; - } - } - - /* @todo: this is not really necessary... */ - ip_data.current_netif = NULL; - ip_data.current_input_netif = NULL; - ip_data.current_ip4_header = NULL; - ip_data.current_ip_header_tot_len = 0; - ip4_addr_set_any(ip4_current_src_addr()); - ip4_addr_set_any(ip4_current_dest_addr()); - - 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 LWIP_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 == LWIP_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 == IP4_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 -ip4_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, - u8_t ttl, u8_t tos, - u8_t proto, struct netif *netif) -{ -#if IP_OPTIONS_SEND - return ip4_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 -ip4_output_if_opt(struct pbuf *p, const ip4_addr_t *src, const ip4_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 */ - const ip4_addr_t *src_used = src; - if (dest != LWIP_IP_HDRINCL) { - if (ip4_addr_isany(src)) { - src_used = netif_ip4_addr(netif); - } - } - -#if IP_OPTIONS_SEND - return ip4_output_if_opt_src(p, src_used, dest, ttl, tos, proto, netif, - ip_options, optlen); -#else /* IP_OPTIONS_SEND */ - return ip4_output_if_src(p, src_used, dest, ttl, tos, proto, netif); -#endif /* IP_OPTIONS_SEND */ -} - -/** - * Same as ip_output_if() but 'src' address is not replaced by netif address - * when it is 'any'. - */ -err_t -ip4_output_if_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, - u8_t ttl, u8_t tos, - u8_t proto, struct netif *netif) -{ -#if IP_OPTIONS_SEND - return ip4_output_if_opt_src(p, src, dest, ttl, tos, proto, netif, NULL, 0); -} - -/** - * Same as ip_output_if_opt() but 'src' address is not replaced by netif address - * when it is 'any'. - */ -err_t -ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_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; - ip4_addr_t dest_addr; -#if CHECKSUM_GEN_IP_INLINE - u32_t chk_sum = 0; -#endif /* CHECKSUM_GEN_IP_INLINE */ - - LWIP_ASSERT_CORE_LOCKED(); - LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); - - MIB2_STATS_INC(mib2.ipoutrequests); - - /* Should the IP header be generated or is it already included in p? */ - if (dest != LWIP_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 */ - if (optlen > (IP_HLEN_MAX - IP_HLEN)) { - /* optlen too long */ - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output_if_opt: optlen too long\n")); - IP_STATS_INC(ip.err); - MIB2_STATS_INC(mib2.ipoutdiscards); - return ERR_VAL; - } - /* round up to a multiple of 4 */ - optlen_aligned = (u16_t)((optlen + 3) & ~3); - ip_hlen = (u16_t)(ip_hlen + optlen_aligned); - /* First write in the IP options */ - if (pbuf_add_header(p, optlen_aligned)) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output_if_opt: not enough room for IP options in pbuf\n")); - IP_STATS_INC(ip.err); - MIB2_STATS_INC(mib2.ipoutdiscards); - return ERR_BUF; - } - MEMCPY(p->payload, ip_options, optlen); - if (optlen < optlen_aligned) { - /* zero the remaining bytes */ - memset(((char *)p->payload) + optlen, 0, (size_t)(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_add_header(p, IP_HLEN)) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output: not enough room for IP header in pbuf\n")); - - IP_STATS_INC(ip.err); - MIB2_STATS_INC(mib2.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 += PP_NTOHS(proto | (ttl << 8)); -#endif /* CHECKSUM_GEN_IP_INLINE */ - - /* dest cannot be NULL here */ - ip4_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_VHL_SET(iphdr, 4, ip_hlen / 4); - IPH_TOS_SET(iphdr, tos); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += PP_NTOHS(tos | (iphdr->_v_hl << 8)); -#endif /* CHECKSUM_GEN_IP_INLINE */ - IPH_LEN_SET(iphdr, lwip_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, lwip_htons(ip_id)); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += iphdr->_id; -#endif /* CHECKSUM_GEN_IP_INLINE */ - ++ip_id; - - if (src == NULL) { - ip4_addr_copy(iphdr->src, *IP4_ADDR_ANY4); - } else { - /* src cannot be NULL here */ - ip4_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; - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { - iphdr->_chksum = (u16_t)chk_sum; /* network order */ - } -#if LWIP_CHECKSUM_CTRL_PER_NETIF - else { - IPH_CHKSUM_SET(iphdr, 0); - } -#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/ -#else /* CHECKSUM_GEN_IP_INLINE */ - IPH_CHKSUM_SET(iphdr, 0); -#if CHECKSUM_GEN_IP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); - } -#endif /* CHECKSUM_GEN_IP */ -#endif /* CHECKSUM_GEN_IP_INLINE */ - } else { - /* IP header already included in p */ - if (p->len < IP_HLEN) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output: LWIP_IP_HDRINCL but pbuf is too short\n")); - IP_STATS_INC(ip.err); - MIB2_STATS_INC(mib2.ipoutdiscards); - return ERR_BUF; - } - iphdr = (struct ip_hdr *)p->payload; - ip4_addr_copy(dest_addr, iphdr->dest); - dest = &dest_addr; - } - - IP_STATS_INC(ip.xmit); - - LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], (u16_t)netif->num)); - ip4_debug_print(p); - -#if ENABLE_LOOPBACK - if (ip4_addr_cmp(dest, netif_ip4_addr(netif)) -#if !LWIP_HAVE_LOOPIF - || ip4_addr_isloopback(dest) -#endif /* !LWIP_HAVE_LOOPIF */ - ) { - /* Packet to self, enqueue it for loopback */ - LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); - return netif_loop_output(netif, p); - } -#if LWIP_MULTICAST_TX_OPTIONS - if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { - netif_loop_output(netif, p); - } -#endif /* LWIP_MULTICAST_TX_OPTIONS */ -#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 ip4_frag(p, netif, dest); - } -#endif /* IP_FRAG */ - - LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: call 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 == LWIP_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 == IP4_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 -ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto) -{ - struct netif *netif; - - LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); - - if ((netif = ip4_route_src(src, dest)) == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip4_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 ip4_output_if(p, src, dest, ttl, tos, proto, netif); -} - -#if LWIP_NETIF_USE_HINTS -/** 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 == LWIP_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 == IP4_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_hint netif output hint pointer set to netif->hint before - * calling ip_output_if() - * - * @return ERR_RTE if no route is found - * see ip_output_if() for more return values - */ -err_t -ip4_output_hinted(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, struct netif_hint *netif_hint) -{ - struct netif *netif; - err_t err; - - LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); - - if ((netif = ip4_route_src(src, dest)) == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip4_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); - IP_STATS_INC(ip.rterr); - return ERR_RTE; - } - - NETIF_SET_HINTS(netif, netif_hint); - err = ip4_output_if(p, src, dest, ttl, tos, proto, netif); - NETIF_RESET_HINTS(netif); - - return err; -} -#endif /* LWIP_NETIF_USE_HINTS*/ - -#if IP_DEBUG -/* Print an IP header by using LWIP_DEBUGF - * @param p an IP packet, p->payload pointing to the IP header - */ -void -ip4_debug_print(struct pbuf *p) -{ - struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; - - 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", - (u16_t)IPH_V(iphdr), - (u16_t)IPH_HL(iphdr), - (u16_t)IPH_TOS(iphdr), - lwip_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", - lwip_ntohs(IPH_ID(iphdr)), - (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 15 & 1), - (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 14 & 1), - (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 13 & 1), - (u16_t)(lwip_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", - (u16_t)IPH_TTL(iphdr), - (u16_t)IPH_PROTO(iphdr), - lwip_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_val(iphdr->src), - ip4_addr2_16_val(iphdr->src), - ip4_addr3_16_val(iphdr->src), - ip4_addr4_16_val(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_val(iphdr->dest), - ip4_addr2_16_val(iphdr->dest), - ip4_addr3_16_val(iphdr->dest), - ip4_addr4_16_val(iphdr->dest))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); -} -#endif /* IP_DEBUG */ - -#endif /* LWIP_IPV4 */ diff --git a/core/c/core/ipv4/ip4_addr.c b/core/c/core/ipv4/ip4_addr.c deleted file mode 100755 index 92077c2..0000000 --- a/core/c/core/ipv4/ip4_addr.c +++ /dev/null @@ -1,321 +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" - -#if LWIP_IPV4 - -#include "lwip/ip_addr.h" -#include "lwip/netif.h" - -/* used by IP4_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */ -const ip_addr_t ip_addr_any = IPADDR4_INIT(IPADDR_ANY); -const ip_addr_t ip_addr_broadcast = IPADDR4_INIT(IPADDR_BROADCAST); - -/** - * Determine if an address is a broadcast address on a network interface - * - * @param addr address to be checked - * @param netif the network interface against which the address is checked - * @return returns non-zero if the address is a broadcast address - */ -u8_t -ip4_addr_isbroadcast_u32(u32_t addr, const struct netif *netif) -{ - ip4_addr_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_ip4_addr(netif))) { - return 0; - /* on the same (sub) network... */ - } else if (ip4_addr_netcmp(&ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) - /* ...and host identifier bits are all ones? =>... */ - && ((addr & ~ip4_addr_get_u32(netif_ip4_netmask(netif))) == - (IPADDR_BROADCAST & ~ip4_addr_get_u32(netif_ip4_netmask(netif))))) { - /* => network broadcast address */ - return 1; - } else { - return 0; - } -} - -/** Checks if a netmask is valid (starting with ones, then only zeros) - * - * @param netmask the IPv4 netmask to check (in network byte order!) - * @return 1 if the netmask is valid, 0 if it is not - */ -u8_t -ip4_addr_netmask_valid(u32_t netmask) -{ - u32_t mask; - u32_t nm_hostorder = lwip_htonl(netmask); - - /* first, check for the first zero */ - for (mask = 1UL << 31 ; mask != 0; mask >>= 1) { - if ((nm_hostorder & mask) == 0) { - break; - } - } - /* then check that there is no one */ - for (; mask != 0; mask >>= 1) { - if ((nm_hostorder & mask) != 0) { - /* there is a one after the first zero -> invalid */ - return 0; - } - } - /* no one after the first zero -> valid */ - return 1; -} - -/** - * Ascii internet address interpretation routine. - * The value returned is in network order. - * - * @param cp IP address in ascii representation (e.g. "127.0.0.1") - * @return ip address in network order - */ -u32_t -ipaddr_addr(const char *cp) -{ - ip4_addr_t val; - - if (ip4addr_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 representation (e.g. "127.0.0.1") - * @param addr pointer to which to save the ip address in network order - * @return 1 if cp could be converted to addr, 0 on failure - */ -int -ip4addr_aton(const char *cp, ip4_addr_t *addr) -{ - u32_t val; - u8_t base; - char c; - u32_t parts[4]; - u32_t *pp = parts; - - c = *cp; - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, 1-9=decimal. - */ - if (!lwip_isdigit(c)) { - return 0; - } - val = 0; - base = 10; - if (c == '0') { - c = *++cp; - if (c == 'x' || c == 'X') { - base = 16; - c = *++cp; - } else { - base = 8; - } - } - for (;;) { - if (lwip_isdigit(c)) { - val = (val * base) + (u32_t)(c - '0'); - c = *++cp; - } else if (base == 16 && lwip_isxdigit(c)) { - val = (val << 4) | (u32_t)(c + 10 - (lwip_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' && !lwip_isspace(c)) { - return 0; - } - /* - * Concoct the address according to - * the number of parts specified. - */ - switch (pp - parts + 1) { - - case 0: - return 0; /* initial nondigit */ - - case 1: /* a -- 32 bits */ - break; - - case 2: /* a.b -- 8.24 bits */ - if (val > 0xffffffUL) { - return 0; - } - if (parts[0] > 0xff) { - return 0; - } - val |= parts[0] << 24; - break; - - case 3: /* a.b.c -- 8.8.16 bits */ - if (val > 0xffff) { - return 0; - } - if ((parts[0] > 0xff) || (parts[1] > 0xff)) { - return 0; - } - val |= (parts[0] << 24) | (parts[1] << 16); - break; - - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if (val > 0xff) { - return 0; - } - if ((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) { - return 0; - } - val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); - break; - default: - LWIP_ASSERT("unhandled", 0); - break; - } - if (addr) { - ip4_addr_set_u32(addr, lwip_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 - * representation of addr - */ -char * -ip4addr_ntoa(const ip4_addr_t *addr) -{ - static char str[IP4ADDR_STRLEN_MAX]; - return ip4addr_ntoa_r(addr, str, IP4ADDR_STRLEN_MAX); -} - -/** - * Same as ip4addr_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 * -ip4addr_ntoa_r(const ip4_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++] = (char)('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; -} - -#endif /* LWIP_IPV4 */ diff --git a/core/c/core/ipv4/ip4_frag.c b/core/c/core/ipv4/ip4_frag.c deleted file mode 100755 index b2fd14c..0000000 --- a/core/c/core/ipv4/ip4_frag.c +++ /dev/null @@ -1,894 +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" - -#if LWIP_IPV4 - -#include "lwip/ip4_frag.h" -#include "lwip/def.h" -#include "lwip/inet_chksum.h" -#include "lwip/netif.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 - -#define IP_REASS_VALIDATE_TELEGRAM_FINISHED 1 -#define IP_REASS_VALIDATE_PBUF_QUEUED 0 -#define IP_REASS_VALIDATE_PBUF_DROPPED -1 - -/** 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) \ - (ip4_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \ - ip4_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); -static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); - -/** - * 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; - u16_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); - } - - MIB2_STATS_INC(mib2.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 = (u16_t)(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 = (u16_t)(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 >= pbufs_freed", ip_reass_pbufcount >= pbufs_freed); - ip_reass_pbufcount = (u16_t)(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, *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; - oldest_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; - oldest_prev = prev; - } else if (r->timer <= oldest->timer) { - /* older than the previous oldest */ - oldest = r; - oldest_prev = prev; - } - } - if (r->next != NULL) { - prev = r; - } - r = r->next; - } - if (oldest != NULL) { - pbufs_freed_current = ip_reass_free_complete_datagram(oldest, 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 * -ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen) -{ - struct ip_reassdata *ipr; -#if ! IP_REASS_FREE_OLDEST - LWIP_UNUSED_ARG(clen); -#endif - - /* No matching previous fragment found, allocate a new reassdata struct */ - ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); - if (ipr == NULL) { -#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; - } - } - 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 -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_reassdata 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 ipr points to the reassembly state - * @param new_p points to the pbuf for the current fragment - * @param is_last is 1 if this pbuf has MF==0 (ipr->flags not updated yet) - * @return see IP_REASS_VALIDATE_* defines - */ -static int -ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p, int is_last) -{ - struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev = NULL; - struct pbuf *q; - u16_t offset, len; - u8_t hlen; - struct ip_hdr *fraghdr; - int valid = 1; - - /* Extract length and fragment offset from current fragment */ - fraghdr = (struct ip_hdr *)new_p->payload; - len = lwip_ntohs(IPH_LEN(fraghdr)); - hlen = IPH_HL_BYTES(fraghdr); - if (hlen > len) { - /* invalid datagram */ - return IP_REASS_VALIDATE_PBUF_DROPPED; - } - len = (u16_t)(len - hlen); - offset = IPH_OFFSET_BYTES(fraghdr); - - /* 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 = (u16_t)(offset + len); - if (iprh->end < offset) { - /* u16_t overflow, cannot handle this */ - return IP_REASS_VALIDATE_PBUF_DROPPED; - } - - /* Iterate through until we either get to the end of the list (append), - * or we find one 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 */ - return IP_REASS_VALIDATE_PBUF_DROPPED; - } -#endif /* IP_REASS_CHECK_OVERLAP */ - iprh_prev->next_pbuf = new_p; - if (iprh_prev->end != iprh->start) { - /* There is a fragment missing between the current - * and the previous fragment */ - valid = 0; - } - } else { -#if IP_REASS_CHECK_OVERLAP - if (iprh->end > iprh_tmp->start) { - /* fragment overlaps with following, throw away */ - return IP_REASS_VALIDATE_PBUF_DROPPED; - } -#endif /* IP_REASS_CHECK_OVERLAP */ - /* 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 */ - return IP_REASS_VALIDATE_PBUF_DROPPED; -#if IP_REASS_CHECK_OVERLAP - } else if (iprh->start < iprh_tmp->end) { - /* overlap: no need to keep the new datagram */ - return IP_REASS_VALIDATE_PBUF_DROPPED; -#endif /* IP_REASS_CHECK_OVERLAP */ - } else { - /* Check if the fragments received so far have no holes. */ - 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 (is_last || ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0)) { - /* and had no holes so far */ - if (valid) { - /* then check if the rest of the fragments is here */ - /* Check if the queue starts with the first datagram */ - if ((ipr->p == NULL) || (((struct ip_reass_helper *)ipr->p->payload)->start != 0)) { - valid = 0; - } else { - /* and check that there are no holes 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); - } - } - } - /* 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 ? IP_REASS_VALIDATE_TELEGRAM_FINISHED : IP_REASS_VALIDATE_PBUF_QUEUED; - } - /* If we come here, not all fragments were received, yet! */ - return IP_REASS_VALIDATE_PBUF_QUEUED; /* not yet valid! */ -} - -/** - * 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 * -ip4_reass(struct pbuf *p) -{ - struct pbuf *r; - struct ip_hdr *fraghdr; - struct ip_reassdata *ipr; - struct ip_reass_helper *iprh; - u16_t offset, len, clen; - u8_t hlen; - int valid; - int is_last; - - IPFRAG_STATS_INC(ip_frag.recv); - MIB2_STATS_INC(mib2.ipreasmreqds); - - fraghdr = (struct ip_hdr *)p->payload; - - if (IPH_HL_BYTES(fraghdr) != IP_HLEN) { - LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: IP options currently not supported!\n")); - IPFRAG_STATS_INC(ip_frag.err); - goto nullreturn; - } - - offset = IPH_OFFSET_BYTES(fraghdr); - len = lwip_ntohs(IPH_LEN(fraghdr)); - hlen = IPH_HL_BYTES(fraghdr); - if (hlen > len) { - /* invalid datagram */ - goto nullreturn; - } - len = (u16_t)(len - hlen); - - /* 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, ("ip4_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, ("ip4_reass: matching previous fragment ID=%"X16_F"\n", - lwip_ntohs(IPH_ID(fraghdr)))); - IPFRAG_STATS_INC(ip_frag.cachehit); - break; - } - } - - 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 (((lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && - ((lwip_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); - } - } - - /* 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*/ - is_last = (IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0; - if (is_last) { - u16_t datagram_len = (u16_t)(offset + len); - if ((datagram_len < offset) || (datagram_len > (0xFFFF - IP_HLEN))) { - /* u16_t overflow, cannot handle this */ - goto nullreturn_ipr; - } - } - /* find the right place to insert this pbuf */ - /* @todo: trim pbufs if fragments are overlapping */ - valid = ip_reass_chain_frag_into_datagram_and_validate(ipr, p, is_last); - if (valid == IP_REASS_VALIDATE_PBUF_DROPPED) { - goto nullreturn_ipr; - } - /* if we come here, the pbuf has been enqueued */ - - /* 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 - (overflow checked by testing against IP_REASS_MAX_PBUFS) */ - ip_reass_pbufcount = (u16_t)(ip_reass_pbufcount + clen); - if (is_last) { - u16_t datagram_len = (u16_t)(offset + len); - ipr->datagram_len = datagram_len; - ipr->flags |= IP_REASS_FLAG_LASTFRAG; - LWIP_DEBUGF(IP_REASS_DEBUG, - ("ip4_reass: last fragment seen, total len %"S16_F"\n", - ipr->datagram_len)); - } - - if (valid == IP_REASS_VALIDATE_TELEGRAM_FINISHED) { - struct ip_reassdata *ipr_prev; - /* the totally last fragment (flag more fragments = 0) was received at least - * once AND all fragments are received */ - u16_t datagram_len = (u16_t)(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, lwip_htons(datagram_len)); - IPH_OFFSET_SET(fraghdr, 0); - IPH_CHKSUM_SET(fraghdr, 0); - /* @todo: do we need to set/calculate the correct checksum? */ -#if CHECKSUM_GEN_IP - IF__NETIF_CHECKSUM_ENABLED(ip_current_input_netif(), NETIF_CHECKSUM_GEN_IP) { - IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN)); - } -#endif /* CHECKSUM_GEN_IP */ - - 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 succeeding fragment */ - pbuf_remove_header(r, IP_HLEN); - pbuf_cat(p, r); - r = iprh->next_pbuf; - } - - /* find the previous entry in the linked list */ - if (ipr == reassdatagrams) { - ipr_prev = NULL; - } else { - for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { - if (ipr_prev->next == ipr) { - break; - } - } - } - - /* release the sources allocate for the fragment queue entry */ - ip_reass_dequeue_datagram(ipr, ipr_prev); - - /* and adjust the number of pbufs currently queued for reassembly. */ - clen = pbuf_clen(p); - LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= clen); - ip_reass_pbufcount = (u16_t)(ip_reass_pbufcount - clen); - - MIB2_STATS_INC(mib2.ipreasmoks); - - /* 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_ipr: - LWIP_ASSERT("ipr != NULL", ipr != NULL); - if (ipr->p == NULL) { - /* dropped pbuf after creating a new datagram entry: remove the entry, too */ - LWIP_ASSERT("not firstalthough just enqueued", ipr == reassdatagrams); - ip_reass_dequeue_datagram(ipr, NULL); - } - -nullreturn: - LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: nullreturn\n")); - IPFRAG_STATS_INC(ip_frag.drop); - pbuf_free(p); - return NULL; -} -#endif /* IP_REASSEMBLY */ - -#if IP_FRAG -#if !LWIP_NETIF_TX_SINGLE_PBUF -/** Allocate a new struct pbuf_custom_ref */ -static struct pbuf_custom_ref * -ip_frag_alloc_pbuf_custom_ref(void) -{ - return (struct pbuf_custom_ref *)memp_malloc(MEMP_FRAG_PBUF); -} - -/** Free a struct pbuf_custom_ref */ -static void -ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref *p) -{ - LWIP_ASSERT("p != NULL", p != NULL); - memp_free(MEMP_FRAG_PBUF, p); -} - -/** Free-callback function to free a 'struct pbuf_custom_ref', called by - * pbuf_free. */ -static void -ipfrag_free_pbuf_custom(struct pbuf *p) -{ - struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref *)p; - LWIP_ASSERT("pcr != NULL", pcr != NULL); - LWIP_ASSERT("pcr == p", (void *)pcr == (void *)p); - if (pcr->original != NULL) { - pbuf_free(pcr->original); - } - ip_frag_free_pbuf_custom_ref(pcr); -} -#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ - -/** - * Fragment an IP datagram if too large for the netif. - * - * Chop the datagram in MTU sized chunks and send them in order - * by pointing PBUF_REFs into p. - * - * @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 -ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest) -{ - struct pbuf *rambuf; -#if !LWIP_NETIF_TX_SINGLE_PBUF - struct pbuf *newpbuf; - u16_t newpbuflen = 0; - u16_t left_to_copy; -#endif - struct ip_hdr *original_iphdr; - struct ip_hdr *iphdr; - const u16_t nfb = (u16_t)((netif->mtu - IP_HLEN) / 8); - u16_t left, fragsize; - u16_t ofo; - int last; - u16_t poff = IP_HLEN; - u16_t tmp; - int mf_set; - - original_iphdr = (struct ip_hdr *)p->payload; - iphdr = original_iphdr; - if (IPH_HL_BYTES(iphdr) != IP_HLEN) { - /* ip4_frag() does not support IP options */ - return ERR_VAL; - } - LWIP_ERROR("ip4_frag(): pbuf too short", p->len >= IP_HLEN, return ERR_VAL); - - /* Save original offset */ - tmp = lwip_ntohs(IPH_OFFSET(iphdr)); - ofo = tmp & IP_OFFMASK; - /* already fragmented? if so, the last fragment we create must have MF, too */ - mf_set = tmp & IP_MF; - - left = (u16_t)(p->tot_len - IP_HLEN); - - while (left) { - /* Fill this fragment */ - fragsize = LWIP_MIN(left, (u16_t)(nfb * 8)); - -#if LWIP_NETIF_TX_SINGLE_PBUF - rambuf = pbuf_alloc(PBUF_IP, fragsize, PBUF_RAM); - if (rambuf == NULL) { - goto memerr; - } - LWIP_ASSERT("this needs a pbuf in one piece!", - (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); - poff += pbuf_copy_partial(p, rambuf->payload, fragsize, poff); - /* make room for the IP header */ - if (pbuf_add_header(rambuf, IP_HLEN)) { - pbuf_free(rambuf); - goto memerr; - } - /* fill in the IP header */ - SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); - iphdr = (struct ip_hdr *)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) { - goto memerr; - } - LWIP_ASSERT("this needs a pbuf in one piece!", - (rambuf->len >= (IP_HLEN))); - SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); - iphdr = (struct ip_hdr *)rambuf->payload; - - left_to_copy = fragsize; - while (left_to_copy) { - struct pbuf_custom_ref *pcr; - u16_t plen = (u16_t)(p->len - poff); - LWIP_ASSERT("p->len >= poff", p->len >= poff); - newpbuflen = LWIP_MIN(left_to_copy, plen); - /* Is this pbuf already empty? */ - if (!newpbuflen) { - poff = 0; - p = p->next; - continue; - } - pcr = ip_frag_alloc_pbuf_custom_ref(); - if (pcr == NULL) { - pbuf_free(rambuf); - goto memerr; - } - /* Mirror this pbuf, although we might not need all of it. */ - newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, - (u8_t *)p->payload + poff, newpbuflen); - if (newpbuf == NULL) { - ip_frag_free_pbuf_custom_ref(pcr); - pbuf_free(rambuf); - goto memerr; - } - 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 = (u16_t)(left_to_copy - newpbuflen); - if (left_to_copy) { - poff = 0; - p = p->next; - } - } - poff = (u16_t)(poff + newpbuflen); -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - - /* Correct header */ - last = (left <= netif->mtu - IP_HLEN); - - /* Set new offset and MF flag */ - tmp = (IP_OFFMASK & (ofo)); - if (!last || mf_set) { - /* the last fragment has MF set if the input frame had it */ - tmp = tmp | IP_MF; - } - IPH_OFFSET_SET(iphdr, lwip_htons(tmp)); - IPH_LEN_SET(iphdr, lwip_htons((u16_t)(fragsize + IP_HLEN))); - IPH_CHKSUM_SET(iphdr, 0); -#if CHECKSUM_GEN_IP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); - } -#endif /* CHECKSUM_GEN_IP */ - - /* 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); - left = (u16_t)(left - fragsize); - ofo = (u16_t)(ofo + nfb); - } - MIB2_STATS_INC(mib2.ipfragoks); - return ERR_OK; -memerr: - MIB2_STATS_INC(mib2.ipfragfails); - return ERR_MEM; -} -#endif /* IP_FRAG */ - -#endif /* LWIP_IPV4 */ diff --git a/core/c/core/ipv6/dhcp6.c b/core/c/core/ipv6/dhcp6.c deleted file mode 100755 index 1ae8742..0000000 --- a/core/c/core/ipv6/dhcp6.c +++ /dev/null @@ -1,812 +0,0 @@ -/** - * @file - * - * @defgroup dhcp6 DHCPv6 - * @ingroup ip6 - * DHCPv6 client: IPv6 address autoconfiguration as per - * RFC 3315 (stateful DHCPv6) and - * RFC 3736 (stateless DHCPv6). - * - * For now, only stateless DHCPv6 is implemented! - * - * TODO: - * - enable/disable API to not always start when RA is received - * - stateful DHCPv6 (for now, only stateless DHCPv6 for DNS and NTP servers works) - * - create Client Identifier? - * - only start requests if a valid local address is available on the netif - * - only start information requests if required (not for every RA) - * - * dhcp6_enable_stateful() enables stateful DHCPv6 for a netif (stateless disabled)\n - * dhcp6_enable_stateless() enables stateless DHCPv6 for a netif (stateful disabled)\n - * dhcp6_disable() disable DHCPv6 for a netif - * - * When enabled, requests are only issued after receipt of RA with the - * corresponding bits set. - */ - -/* - * Copyright (c) 2018 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - */ - -#include "lwip/opt.h" - -#if LWIP_IPV6 && LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/dhcp6.h" -#include "lwip/prot/dhcp6.h" -#include "lwip/def.h" -#include "lwip/udp.h" -#include "lwip/dns.h" - -#include - -#ifdef LWIP_HOOK_FILENAME -#include LWIP_HOOK_FILENAME -#endif -#ifndef LWIP_HOOK_DHCP6_APPEND_OPTIONS -#define LWIP_HOOK_DHCP6_APPEND_OPTIONS(netif, dhcp6, state, msg, msg_type, options_len_ptr, max_len) -#endif -#ifndef LWIP_HOOK_DHCP6_PARSE_OPTION -#define LWIP_HOOK_DHCP6_PARSE_OPTION(netif, dhcp6, state, msg, msg_type, option, len, pbuf, offset) do { LWIP_UNUSED_ARG(msg); } while(0) -#endif - -#if LWIP_DNS && LWIP_DHCP6_MAX_DNS_SERVERS -#if DNS_MAX_SERVERS > LWIP_DHCP6_MAX_DNS_SERVERS -#define LWIP_DHCP6_PROVIDE_DNS_SERVERS LWIP_DHCP6_MAX_DNS_SERVERS -#else -#define LWIP_DHCP6_PROVIDE_DNS_SERVERS DNS_MAX_SERVERS -#endif -#else -#define LWIP_DHCP6_PROVIDE_DNS_SERVERS 0 -#endif - - -/** Option handling: options are parsed in dhcp6_parse_reply - * and saved in an array where other functions can load them from. - * This might be moved into the struct dhcp6 (not necessarily since - * lwIP is single-threaded and the array is only used while in recv - * callback). */ -enum dhcp6_option_idx { - DHCP6_OPTION_IDX_CLI_ID = 0, - DHCP6_OPTION_IDX_SERVER_ID, -#if LWIP_DHCP6_PROVIDE_DNS_SERVERS - DHCP6_OPTION_IDX_DNS_SERVER, - DHCP6_OPTION_IDX_DOMAIN_LIST, -#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ -#if LWIP_DHCP6_GET_NTP_SRV - DHCP6_OPTION_IDX_NTP_SERVER, -#endif /* LWIP_DHCP_GET_NTP_SRV */ - DHCP6_OPTION_IDX_MAX -}; - -struct dhcp6_option_info { - u8_t option_given; - u16_t val_start; - u16_t val_length; -}; - -/** Holds the decoded option info, only valid while in dhcp6_recv. */ -struct dhcp6_option_info dhcp6_rx_options[DHCP6_OPTION_IDX_MAX]; - -#define dhcp6_option_given(dhcp6, idx) (dhcp6_rx_options[idx].option_given != 0) -#define dhcp6_got_option(dhcp6, idx) (dhcp6_rx_options[idx].option_given = 1) -#define dhcp6_clear_option(dhcp6, idx) (dhcp6_rx_options[idx].option_given = 0) -#define dhcp6_clear_all_options(dhcp6) (memset(dhcp6_rx_options, 0, sizeof(dhcp6_rx_options))) -#define dhcp6_get_option_start(dhcp6, idx) (dhcp6_rx_options[idx].val_start) -#define dhcp6_get_option_length(dhcp6, idx) (dhcp6_rx_options[idx].val_length) -#define dhcp6_set_option(dhcp6, idx, start, len) do { dhcp6_rx_options[idx].val_start = (start); dhcp6_rx_options[idx].val_length = (len); }while(0) - - -const ip_addr_t dhcp6_All_DHCP6_Relay_Agents_and_Servers = IPADDR6_INIT_HOST(0xFF020000, 0, 0, 0x00010002); -const ip_addr_t dhcp6_All_DHCP6_Servers = IPADDR6_INIT_HOST(0xFF020000, 0, 0, 0x00010003); - -static struct udp_pcb *dhcp6_pcb; -static u8_t dhcp6_pcb_refcount; - - -/* receive, unfold, parse and free incoming messages */ -static void dhcp6_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); - -/** Ensure DHCP PCB is allocated and bound */ -static err_t -dhcp6_inc_pcb_refcount(void) -{ - if (dhcp6_pcb_refcount == 0) { - LWIP_ASSERT("dhcp6_inc_pcb_refcount(): memory leak", dhcp6_pcb == NULL); - - /* allocate UDP PCB */ - dhcp6_pcb = udp_new_ip6(); - - if (dhcp6_pcb == NULL) { - return ERR_MEM; - } - - ip_set_option(dhcp6_pcb, SOF_BROADCAST); - - /* set up local and remote port for the pcb -> listen on all interfaces on all src/dest IPs */ - udp_bind(dhcp6_pcb, IP6_ADDR_ANY, DHCP6_CLIENT_PORT); - udp_recv(dhcp6_pcb, dhcp6_recv, NULL); - } - - dhcp6_pcb_refcount++; - - return ERR_OK; -} - -/** Free DHCP PCB if the last netif stops using it */ -static void -dhcp6_dec_pcb_refcount(void) -{ - LWIP_ASSERT("dhcp6_pcb_refcount(): refcount error", (dhcp6_pcb_refcount > 0)); - dhcp6_pcb_refcount--; - - if (dhcp6_pcb_refcount == 0) { - udp_remove(dhcp6_pcb); - dhcp6_pcb = NULL; - } -} - -/** - * @ingroup dhcp6 - * Set a statically allocated struct dhcp6 to work with. - * Using this prevents dhcp6_start to allocate it using mem_malloc. - * - * @param netif the netif for which to set the struct dhcp - * @param dhcp6 (uninitialised) dhcp6 struct allocated by the application - */ -void -dhcp6_set_struct(struct netif *netif, struct dhcp6 *dhcp6) -{ - LWIP_ASSERT("netif != NULL", netif != NULL); - LWIP_ASSERT("dhcp6 != NULL", dhcp6 != NULL); - LWIP_ASSERT("netif already has a struct dhcp6 set", netif_dhcp6_data(netif) == NULL); - - /* clear data structure */ - memset(dhcp6, 0, sizeof(struct dhcp6)); - /* dhcp6_set_state(&dhcp, DHCP6_STATE_OFF); */ - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, dhcp6); -} - -/** - * @ingroup dhcp6 - * Removes a struct dhcp6 from a netif. - * - * ATTENTION: Only use this when not using dhcp6_set_struct() to allocate the - * struct dhcp6 since the memory is passed back to the heap. - * - * @param netif the netif from which to remove the struct dhcp - */ -void dhcp6_cleanup(struct netif *netif) -{ - LWIP_ASSERT("netif != NULL", netif != NULL); - - if (netif_dhcp6_data(netif) != NULL) { - mem_free(netif_dhcp6_data(netif)); - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, NULL); - } -} - -static struct dhcp6* -dhcp6_get_struct(struct netif *netif, const char *dbg_requester) -{ - struct dhcp6 *dhcp6 = netif_dhcp6_data(netif); - if (dhcp6 == NULL) { - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("%s: mallocing new DHCPv6 client\n", dbg_requester)); - dhcp6 = (struct dhcp6 *)mem_malloc(sizeof(struct dhcp6)); - if (dhcp6 == NULL) { - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("%s: could not allocate dhcp6\n", dbg_requester)); - return NULL; - } - - /* clear data structure, this implies DHCP6_STATE_OFF */ - memset(dhcp6, 0, sizeof(struct dhcp6)); - /* store this dhcp6 client in the netif */ - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, dhcp6); - } else { - /* already has DHCP6 client attached */ - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("%s: using existing DHCPv6 client\n", dbg_requester)); - } - - if (!dhcp6->pcb_allocated) { - if (dhcp6_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP6 PCB is allocated */ - mem_free(dhcp6); - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, NULL); - return NULL; - } - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("%s: allocated dhcp6", dbg_requester)); - dhcp6->pcb_allocated = 1; - } - return dhcp6; -} - -/* - * Set the DHCPv6 state - * If the state changed, reset the number of tries. - */ -static void -dhcp6_set_state(struct dhcp6 *dhcp6, u8_t new_state, const char *dbg_caller) -{ - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("DHCPv6 state: %d -> %d (%s)\n", - dhcp6->state, new_state, dbg_caller)); - if (new_state != dhcp6->state) { - dhcp6->state = new_state; - dhcp6->tries = 0; - dhcp6->request_timeout = 0; - } -} - -static int -dhcp6_stateless_enabled(struct dhcp6 *dhcp6) -{ - if ((dhcp6->state == DHCP6_STATE_STATELESS_IDLE) || - (dhcp6->state == DHCP6_STATE_REQUESTING_CONFIG)) { - return 1; - } - return 0; -} - -/*static int -dhcp6_stateful_enabled(struct dhcp6 *dhcp6) -{ - if (dhcp6->state == DHCP6_STATE_OFF) { - return 0; - } - if (dhcp6_stateless_enabled(dhcp6)) { - return 0; - } - return 1; -}*/ - -/** - * @ingroup dhcp6 - * Enable stateful DHCPv6 on this netif - * Requests are sent on receipt of an RA message with the - * ND6_RA_FLAG_MANAGED_ADDR_CONFIG flag set. - * - * A struct dhcp6 will be allocated for this netif if not - * set via @ref dhcp6_set_struct before. - * - * @todo: stateful DHCPv6 not supported, yet - */ -err_t -dhcp6_enable_stateful(struct netif *netif) -{ - LWIP_UNUSED_ARG(netif); - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("stateful dhcp6 not implemented yet")); - return ERR_VAL; -} - -/** - * @ingroup dhcp6 - * Enable stateless DHCPv6 on this netif - * Requests are sent on receipt of an RA message with the - * ND6_RA_FLAG_OTHER_CONFIG flag set. - * - * A struct dhcp6 will be allocated for this netif if not - * set via @ref dhcp6_set_struct before. - */ -err_t -dhcp6_enable_stateless(struct netif *netif) -{ - struct dhcp6 *dhcp6; - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_enable_stateless(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - - dhcp6 = dhcp6_get_struct(netif, "dhcp6_enable_stateless()"); - if (dhcp6 == NULL) { - return ERR_MEM; - } - if (dhcp6_stateless_enabled(dhcp6)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): stateless DHCPv6 already enabled")); - return ERR_OK; - } else if (dhcp6->state != DHCP6_STATE_OFF) { - /* stateful running */ - /* @todo: stop stateful once it is implemented */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): switching from stateful to stateless DHCPv6")); - } - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): stateless DHCPv6 enabled\n")); - dhcp6_set_state(dhcp6, DHCP6_STATE_STATELESS_IDLE, "dhcp6_enable_stateless"); - return ERR_OK; -} - -/** - * @ingroup dhcp6 - * Disable stateful or stateless DHCPv6 on this netif - * Requests are sent on receipt of an RA message with the - * ND6_RA_FLAG_OTHER_CONFIG flag set. - */ -void -dhcp6_disable(struct netif *netif) -{ - struct dhcp6 *dhcp6; - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_disable(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - - dhcp6 = netif_dhcp6_data(netif); - if (dhcp6 != NULL) { - if (dhcp6->state != DHCP6_STATE_OFF) { - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_disable(): DHCPv6 disabled (old state: %s)\n", - (dhcp6_stateless_enabled(dhcp6) ? "stateless" : "stateful"))); - dhcp6_set_state(dhcp6, DHCP6_STATE_OFF, "dhcp6_disable"); - if (dhcp6->pcb_allocated != 0) { - dhcp6_dec_pcb_refcount(); /* free DHCPv6 PCB if not needed any more */ - dhcp6->pcb_allocated = 0; - } - } - } -} - -/** - * Create a DHCPv6 request, fill in common headers - * - * @param netif the netif under DHCPv6 control - * @param dhcp6 dhcp6 control struct - * @param message_type message type of the request - * @param opt_len_alloc option length to allocate - * @param options_out_len option length on exit - * @return a pbuf for the message - */ -static struct pbuf * -dhcp6_create_msg(struct netif *netif, struct dhcp6 *dhcp6, u8_t message_type, - u16_t opt_len_alloc, u16_t *options_out_len) -{ - struct pbuf *p_out; - struct dhcp6_msg *msg_out; - - LWIP_ERROR("dhcp6_create_msg: netif != NULL", (netif != NULL), return NULL;); - LWIP_ERROR("dhcp6_create_msg: dhcp6 != NULL", (dhcp6 != NULL), return NULL;); - p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp6_msg) + opt_len_alloc, PBUF_RAM); - if (p_out == NULL) { - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp6_create_msg(): could not allocate pbuf\n")); - return NULL; - } - LWIP_ASSERT("dhcp6_create_msg: check that first pbuf can hold struct dhcp6_msg", - (p_out->len >= sizeof(struct dhcp6_msg) + opt_len_alloc)); - - /* @todo: limit new xid for certain message types? */ - /* reuse transaction identifier in retransmissions */ - if (dhcp6->tries == 0) { - dhcp6->xid = LWIP_RAND() & 0xFFFFFF; - } - - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, - ("transaction id xid(%"X32_F")\n", dhcp6->xid)); - - msg_out = (struct dhcp6_msg *)p_out->payload; - memset(msg_out, 0, sizeof(struct dhcp6_msg) + opt_len_alloc); - - msg_out->msgtype = message_type; - msg_out->transaction_id[0] = (u8_t)(dhcp6->xid >> 16); - msg_out->transaction_id[1] = (u8_t)(dhcp6->xid >> 8); - msg_out->transaction_id[2] = (u8_t)dhcp6->xid; - *options_out_len = 0; - return p_out; -} - -static u16_t -dhcp6_option_short(u16_t options_out_len, u8_t *options, u16_t value) -{ - options[options_out_len++] = (u8_t)((value & 0xff00U) >> 8); - options[options_out_len++] = (u8_t) (value & 0x00ffU); - return options_out_len; -} - -static u16_t -dhcp6_option_optionrequest(u16_t options_out_len, u8_t *options, const u16_t *req_options, - u16_t num_req_options, u16_t max_len) -{ - size_t i; - u16_t ret; - - LWIP_ASSERT("dhcp6_option_optionrequest: options_out_len + sizeof(struct dhcp6_msg) + addlen <= max_len", - sizeof(struct dhcp6_msg) + options_out_len + 4U + (2U * num_req_options) <= max_len); - LWIP_UNUSED_ARG(max_len); - - ret = dhcp6_option_short(options_out_len, options, DHCP6_OPTION_ORO); - ret = dhcp6_option_short(ret, options, 2 * num_req_options); - for (i = 0; i < num_req_options; i++) { - ret = dhcp6_option_short(ret, options, req_options[i]); - } - return ret; -} - -/* All options are added, shrink the pbuf to the required size */ -static void -dhcp6_msg_finalize(u16_t options_out_len, struct pbuf *p_out) -{ - /* shrink the pbuf to the actual content length */ - pbuf_realloc(p_out, (u16_t)(sizeof(struct dhcp6_msg) + options_out_len)); -} - - -#if LWIP_IPV6_DHCP6_STATELESS -static void -dhcp6_information_request(struct netif *netif, struct dhcp6 *dhcp6) -{ - const u16_t requested_options[] = {DHCP6_OPTION_DNS_SERVERS, DHCP6_OPTION_DOMAIN_LIST, DHCP6_OPTION_SNTP_SERVERS}; - u16_t msecs; - struct pbuf *p_out; - u16_t options_out_len; - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_information_request()\n")); - /* create and initialize the DHCP message header */ - p_out = dhcp6_create_msg(netif, dhcp6, DHCP6_INFOREQUEST, 4 + sizeof(requested_options), &options_out_len); - if (p_out != NULL) { - err_t err; - struct dhcp6_msg *msg_out = (struct dhcp6_msg *)p_out->payload; - u8_t *options = (u8_t *)(msg_out + 1); - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_information_request: making request\n")); - - options_out_len = dhcp6_option_optionrequest(options_out_len, options, requested_options, - LWIP_ARRAYSIZE(requested_options), p_out->len); - LWIP_HOOK_DHCP6_APPEND_OPTIONS(netif, dhcp6, DHCP6_STATE_REQUESTING_CONFIG, msg_out, - DHCP6_INFOREQUEST, options_out_len, p_out->len); - dhcp6_msg_finalize(options_out_len, p_out); - - err = udp_sendto_if(dhcp6_pcb, p_out, &dhcp6_All_DHCP6_Relay_Agents_and_Servers, DHCP6_SERVER_PORT, netif); - pbuf_free(p_out); - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_information_request: INFOREQUESTING -> %d\n", (int)err)); - LWIP_UNUSED_ARG(err); - } else { - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp6_information_request: could not allocate DHCP6 request\n")); - } - dhcp6_set_state(dhcp6, DHCP6_STATE_REQUESTING_CONFIG, "dhcp6_information_request"); - if (dhcp6->tries < 255) { - dhcp6->tries++; - } - msecs = (u16_t)((dhcp6->tries < 6 ? 1 << dhcp6->tries : 60) * 1000); - dhcp6->request_timeout = (u16_t)((msecs + DHCP6_TIMER_MSECS - 1) / DHCP6_TIMER_MSECS); - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_information_request(): set request timeout %"U16_F" msecs\n", msecs)); -} - -static err_t -dhcp6_request_config(struct netif *netif, struct dhcp6 *dhcp6) -{ - /* stateless mode enabled and no request running? */ - if (dhcp6->state == DHCP6_STATE_STATELESS_IDLE) { - /* send Information-request and wait for answer; setup receive timeout */ - dhcp6_information_request(netif, dhcp6); - } - - return ERR_OK; -} - -static void -dhcp6_abort_config_request(struct dhcp6 *dhcp6) -{ - if (dhcp6->state == DHCP6_STATE_REQUESTING_CONFIG) { - /* abort running request */ - dhcp6_set_state(dhcp6, DHCP6_STATE_STATELESS_IDLE, "dhcp6_abort_config_request"); - } -} - -/* Handle a REPLY to INFOREQUEST - * This parses DNS and NTP server addresses from the reply. - */ -static void -dhcp6_handle_config_reply(struct netif *netif, struct pbuf *p_msg_in) -{ - struct dhcp6 *dhcp6 = netif_dhcp6_data(netif); - - LWIP_UNUSED_ARG(dhcp6); - LWIP_UNUSED_ARG(p_msg_in); - -#if LWIP_DHCP6_PROVIDE_DNS_SERVERS - if (dhcp6_option_given(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER)) { - ip_addr_t dns_addr; - ip6_addr_t *dns_addr6; - u16_t op_start = dhcp6_get_option_start(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER); - u16_t op_len = dhcp6_get_option_length(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER); - u16_t idx; - u8_t n; - - memset(&dns_addr, 0, sizeof(dns_addr)); - dns_addr6 = ip_2_ip6(&dns_addr); - for (n = 0, idx = op_start; (idx < op_start + op_len) && (n < LWIP_DHCP6_PROVIDE_DNS_SERVERS); - n++, idx += sizeof(struct ip6_addr_packed)) { - u16_t copied = pbuf_copy_partial(p_msg_in, dns_addr6, sizeof(struct ip6_addr_packed), idx); - if (copied != sizeof(struct ip6_addr_packed)) { - /* pbuf length mismatch */ - return; - } - ip6_addr_assign_zone(dns_addr6, IP6_UNKNOWN, netif); - /* @todo: do we need a different offset than DHCP(v4)? */ - dns_setserver(n, &dns_addr); - } - } - /* @ todo: parse and set Domain Search List */ -#endif /* LWIP_DHCP6_PROVIDE_DNS_SERVERS */ - -#if LWIP_DHCP6_GET_NTP_SRV - if (dhcp6_option_given(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER)) { - ip_addr_t ntp_server_addrs[LWIP_DHCP6_MAX_NTP_SERVERS]; - u16_t op_start = dhcp6_get_option_start(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER); - u16_t op_len = dhcp6_get_option_length(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER); - u16_t idx; - u8_t n; - - for (n = 0, idx = op_start; (idx < op_start + op_len) && (n < LWIP_DHCP6_MAX_NTP_SERVERS); - n++, idx += sizeof(struct ip6_addr_packed)) { - u16_t copied; - ip6_addr_t *ntp_addr6 = ip_2_ip6(&ntp_server_addrs[n]); - ip_addr_set_zero_ip6(&ntp_server_addrs[n]); - copied = pbuf_copy_partial(p_msg_in, ntp_addr6, sizeof(struct ip6_addr_packed), idx); - if (copied != sizeof(struct ip6_addr_packed)) { - /* pbuf length mismatch */ - return; - } - ip6_addr_assign_zone(ntp_addr6, IP6_UNKNOWN, netif); - } - dhcp6_set_ntp_servers(n, ntp_server_addrs); - } -#endif /* LWIP_DHCP6_GET_NTP_SRV */ -} -#endif /* LWIP_IPV6_DHCP6_STATELESS */ - -/** This function is called from nd6 module when an RA messsage is received - * It triggers DHCPv6 requests (if enabled). - */ -void -dhcp6_nd6_ra_trigger(struct netif *netif, u8_t managed_addr_config, u8_t other_config) -{ - struct dhcp6 *dhcp6; - - LWIP_ASSERT("netif != NULL", netif != NULL); - dhcp6 = netif_dhcp6_data(netif); - - LWIP_UNUSED_ARG(managed_addr_config); - LWIP_UNUSED_ARG(other_config); - LWIP_UNUSED_ARG(dhcp6); - -#if LWIP_IPV6_DHCP6_STATELESS - if (dhcp6 != NULL) { - if (dhcp6_stateless_enabled(dhcp6)) { - if (other_config) { - dhcp6_request_config(netif, dhcp6); - } else { - dhcp6_abort_config_request(dhcp6); - } - } - } -#endif /* LWIP_IPV6_DHCP6_STATELESS */ -} - -/** - * Parse the DHCPv6 message and extract the DHCPv6 options. - * - * Extract the DHCPv6 options (offset + length) so that we can later easily - * check for them or extract the contents. - */ -static err_t -dhcp6_parse_reply(struct pbuf *p, struct dhcp6 *dhcp6) -{ - u16_t offset; - u16_t offset_max; - u16_t options_idx; - struct dhcp6_msg *msg_in; - - LWIP_UNUSED_ARG(dhcp6); - - /* clear received options */ - dhcp6_clear_all_options(dhcp6); - msg_in = (struct dhcp6_msg *)p->payload; - - /* parse options */ - - options_idx = sizeof(struct dhcp6_msg); - /* parse options to the end of the received packet */ - offset_max = p->tot_len; - - offset = options_idx; - /* at least 4 byte to read? */ - while ((offset + 4 <= offset_max)) { - u8_t op_len_buf[4]; - u8_t *op_len; - u16_t op; - u16_t len; - u16_t val_offset = (u16_t)(offset + 4); - if (val_offset < offset) { - /* overflow */ - return ERR_BUF; - } - /* copy option + length, might be split accross pbufs */ - op_len = (u8_t *)pbuf_get_contiguous(p, op_len_buf, 4, 4, offset); - if (op_len == NULL) { - /* failed to get option and length */ - return ERR_VAL; - } - op = (op_len[0] << 8) | op_len[1]; - len = (op_len[2] << 8) | op_len[3]; - offset = val_offset + len; - if (offset < val_offset) { - /* overflow */ - return ERR_BUF; - } - - switch (op) { - case (DHCP6_OPTION_CLIENTID): - dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_CLI_ID); - dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_CLI_ID, val_offset, len); - break; - case (DHCP6_OPTION_SERVERID): - dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_SERVER_ID); - dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_SERVER_ID, val_offset, len); - break; -#if LWIP_DHCP6_PROVIDE_DNS_SERVERS - case (DHCP6_OPTION_DNS_SERVERS): - dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER); - dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER, val_offset, len); - break; - case (DHCP6_OPTION_DOMAIN_LIST): - dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_DOMAIN_LIST); - dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_DOMAIN_LIST, val_offset, len); - break; -#endif /* LWIP_DHCP6_PROVIDE_DNS_SERVERS */ -#if LWIP_DHCP6_GET_NTP_SRV - case (DHCP6_OPTION_SNTP_SERVERS): - dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER); - dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER, val_offset, len); - break; -#endif /* LWIP_DHCP6_GET_NTP_SRV*/ - default: - LWIP_DEBUGF(DHCP6_DEBUG, ("skipping option %"U16_F" in options\n", op)); - LWIP_HOOK_DHCP6_PARSE_OPTION(ip_current_netif(), dhcp6, dhcp6->state, msg_in, - msg_in->msgtype, op, len, q, val_offset); - break; - } - } - return ERR_OK; -} - -static void -dhcp6_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) -{ - struct netif *netif = ip_current_input_netif(); - struct dhcp6 *dhcp6 = netif_dhcp6_data(netif); - struct dhcp6_msg *reply_msg = (struct dhcp6_msg *)p->payload; - u8_t msg_type; - u32_t xid; - - LWIP_UNUSED_ARG(arg); - - /* Caught DHCPv6 message from netif that does not have DHCPv6 enabled? -> not interested */ - if ((dhcp6 == NULL) || (dhcp6->pcb_allocated == 0)) { - goto free_pbuf_and_return; - } - - LWIP_ERROR("invalid server address type", IP_IS_V6(addr), goto free_pbuf_and_return;); - - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_recv(pbuf = %p) from DHCPv6 server %s port %"U16_F"\n", (void *)p, - ipaddr_ntoa(addr), port)); - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); - LWIP_DEBUGF(DHCP6_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); - - if (p->len < sizeof(struct dhcp6_msg)) { - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCPv6 reply message or pbuf too short\n")); - goto free_pbuf_and_return; - } - - /* match transaction ID against what we expected */ - xid = reply_msg->transaction_id[0] << 16; - xid |= reply_msg->transaction_id[1] << 8; - xid |= reply_msg->transaction_id[2]; - if (xid != dhcp6->xid) { - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("transaction id mismatch reply_msg->xid(%"X32_F")!= dhcp6->xid(%"X32_F")\n", xid, dhcp6->xid)); - goto free_pbuf_and_return; - } - /* option fields could be unfold? */ - if (dhcp6_parse_reply(p, dhcp6) != ERR_OK) { - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("problem unfolding DHCPv6 message - too short on memory?\n")); - goto free_pbuf_and_return; - } - - /* read DHCP message type */ - msg_type = reply_msg->msgtype; - /* message type is DHCP6 REPLY? */ - if (msg_type == DHCP6_REPLY) { - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("DHCP6_REPLY received\n")); -#if LWIP_IPV6_DHCP6_STATELESS - /* in info-requesting state? */ - if (dhcp6->state == DHCP6_STATE_REQUESTING_CONFIG) { - dhcp6_set_state(dhcp6, DHCP6_STATE_STATELESS_IDLE, "dhcp6_recv"); - dhcp6_handle_config_reply(netif, p); - } else -#endif /* LWIP_IPV6_DHCP6_STATELESS */ - { - /* @todo: handle reply in other states? */ - } - } else { - /* @todo: handle other message types */ - } - -free_pbuf_and_return: - pbuf_free(p); -} - -/** - * A DHCPv6 request has timed out. - * - * The timer that was started with the DHCPv6 request has - * timed out, indicating no response was received in time. - */ -static void -dhcp6_timeout(struct netif *netif, struct dhcp6 *dhcp6) -{ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_timeout()\n")); - - LWIP_UNUSED_ARG(netif); - LWIP_UNUSED_ARG(dhcp6); - -#if LWIP_IPV6_DHCP6_STATELESS - /* back-off period has passed, or server selection timed out */ - if (dhcp6->state == DHCP6_STATE_REQUESTING_CONFIG) { - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_timeout(): retrying information request\n")); - dhcp6_information_request(netif, dhcp6); - } -#endif /* LWIP_IPV6_DHCP6_STATELESS */ -} - -/** - * DHCPv6 timeout handling (this function must be called every 500ms, - * see @ref DHCP6_TIMER_MSECS). - * - * A DHCPv6 server is expected to respond within a short period of time. - * This timer checks whether an outstanding DHCPv6 request is timed out. - */ -void -dhcp6_tmr(void) -{ - struct netif *netif; - /* loop through netif's */ - NETIF_FOREACH(netif) { - struct dhcp6 *dhcp6 = netif_dhcp6_data(netif); - /* only act on DHCPv6 configured interfaces */ - if (dhcp6 != NULL) { - /* timer is active (non zero), and is about to trigger now */ - if (dhcp6->request_timeout > 1) { - dhcp6->request_timeout--; - } else if (dhcp6->request_timeout == 1) { - dhcp6->request_timeout--; - /* { dhcp6->request_timeout == 0 } */ - LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_tmr(): request timeout\n")); - /* this client's request timeout triggered */ - dhcp6_timeout(netif, dhcp6); - } - } - } -} - -#endif /* LWIP_IPV6 && LWIP_IPV6_DHCP6 */ diff --git a/core/c/core/ipv6/ethip6.c b/core/c/core/ipv6/ethip6.c deleted file mode 100755 index 0a616b6..0000000 --- a/core/c/core/ipv6/ethip6.c +++ /dev/null @@ -1,123 +0,0 @@ -/** - * @file - * - * Ethernet output for IPv6. Uses ND tables for link-layer addressing. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#include "lwip/opt.h" - -#if LWIP_IPV6 && LWIP_ETHERNET - -#include "lwip/ethip6.h" -#include "lwip/nd6.h" -#include "lwip/pbuf.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/inet_chksum.h" -#include "lwip/netif.h" -#include "lwip/icmp6.h" -#include "lwip/prot/ethernet.h" -#include "netif/ethernet.h" - -#include - -/** - * Resolve and fill-in Ethernet address header for outgoing IPv6 packet. - * - * For IPv6 multicast, corresponding Ethernet addresses - * are selected and the packet is transmitted on the link. - * - * For unicast addresses, ask the ND6 module what to do. It will either let us - * send the the packet right away, or queue the packet for later itself, unless - * an error occurs. - * - * @todo anycast addresses - * - * @param netif The lwIP network interface which the IP packet will be sent on. - * @param q The pbuf(s) containing the IP packet to be sent. - * @param ip6addr The IP address of the packet destination. - * - * @return - * - ERR_OK or the return value of @ref nd6_get_next_hop_addr_or_queue. - */ -err_t -ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) -{ - struct eth_addr dest; - const u8_t *hwaddr; - err_t result; - - LWIP_ASSERT_CORE_LOCKED(); - - /* The destination IP address must be properly zoned from here on down. */ - IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif); - - /* multicast destination IP address? */ - if (ip6_addr_ismulticast(ip6addr)) { - /* Hash IP multicast address to MAC address.*/ - dest.addr[0] = 0x33; - dest.addr[1] = 0x33; - dest.addr[2] = ((const u8_t *)(&(ip6addr->addr[3])))[0]; - dest.addr[3] = ((const u8_t *)(&(ip6addr->addr[3])))[1]; - dest.addr[4] = ((const u8_t *)(&(ip6addr->addr[3])))[2]; - dest.addr[5] = ((const u8_t *)(&(ip6addr->addr[3])))[3]; - - /* Send out. */ - return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6); - } - - /* We have a unicast destination IP address */ - /* @todo anycast? */ - - /* Ask ND6 what to do with the packet. */ - result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr); - if (result != ERR_OK) { - return result; - } - - /* If no hardware address is returned, nd6 has queued the packet for later. */ - if (hwaddr == NULL) { - return ERR_OK; - } - - /* Send out the packet using the returned hardware address. */ - SMEMCPY(dest.addr, hwaddr, 6); - return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6); -} - -#endif /* LWIP_IPV6 && LWIP_ETHERNET */ diff --git a/core/c/core/ipv6/icmp6.c b/core/c/core/ipv6/icmp6.c deleted file mode 100755 index 7c93668..0000000 --- a/core/c/core/ipv6/icmp6.c +++ /dev/null @@ -1,425 +0,0 @@ -/** - * @file - * - * IPv6 version of ICMP, as per RFC 4443. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#include "lwip/opt.h" - -#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/icmp6.h" -#include "lwip/prot/icmp6.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/inet_chksum.h" -#include "lwip/pbuf.h" -#include "lwip/netif.h" -#include "lwip/nd6.h" -#include "lwip/mld6.h" -#include "lwip/ip.h" -#include "lwip/stats.h" - -#include - -#if LWIP_ICMP6_DATASIZE == 0 -#undef LWIP_ICMP6_DATASIZE -#define LWIP_ICMP6_DATASIZE 8 -#endif - -/* Forward declarations */ -static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type); -static void icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data, - u8_t type, const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr); -static void icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data, - u8_t type, const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr, struct netif *netif); - - -/** - * Process an input ICMPv6 message. Called by ip6_input. - * - * Will generate a reply for echo requests. Other messages are forwarded - * to nd6_input, or mld6_input. - * - * @param p the mld packet, p->payload pointing to the icmpv6 header - * @param inp the netif on which this packet was received - */ -void -icmp6_input(struct pbuf *p, struct netif *inp) -{ - struct icmp6_hdr *icmp6hdr; - struct pbuf *r; - const ip6_addr_t *reply_src; - - ICMP6_STATS_INC(icmp6.recv); - - /* Check that ICMPv6 header fits in payload */ - if (p->len < sizeof(struct icmp6_hdr)) { - /* drop short packets */ - pbuf_free(p); - ICMP6_STATS_INC(icmp6.lenerr); - ICMP6_STATS_INC(icmp6.drop); - return; - } - - icmp6hdr = (struct icmp6_hdr *)p->payload; - -#if CHECKSUM_CHECK_ICMP6 - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) { - if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(), - ip6_current_dest_addr()) != 0) { - /* Checksum failed */ - pbuf_free(p); - ICMP6_STATS_INC(icmp6.chkerr); - ICMP6_STATS_INC(icmp6.drop); - return; - } - } -#endif /* CHECKSUM_CHECK_ICMP6 */ - - switch (icmp6hdr->type) { - case ICMP6_TYPE_NA: /* Neighbor advertisement */ - case ICMP6_TYPE_NS: /* Neighbor solicitation */ - case ICMP6_TYPE_RA: /* Router advertisement */ - case ICMP6_TYPE_RD: /* Redirect */ - case ICMP6_TYPE_PTB: /* Packet too big */ - nd6_input(p, inp); - return; - case ICMP6_TYPE_RS: -#if LWIP_IPV6_FORWARD - /* @todo implement router functionality */ -#endif - break; -#if LWIP_IPV6_MLD - case ICMP6_TYPE_MLQ: - case ICMP6_TYPE_MLR: - case ICMP6_TYPE_MLD: - mld6_input(p, inp); - return; -#endif - case ICMP6_TYPE_EREQ: -#if !LWIP_MULTICAST_PING - /* multicast destination address? */ - if (ip6_addr_ismulticast(ip6_current_dest_addr())) { - /* drop */ - pbuf_free(p); - ICMP6_STATS_INC(icmp6.drop); - return; - } -#endif /* LWIP_MULTICAST_PING */ - - /* Allocate reply. */ - r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM); - if (r == NULL) { - /* drop */ - pbuf_free(p); - ICMP6_STATS_INC(icmp6.memerr); - return; - } - - /* Copy echo request. */ - if (pbuf_copy(r, p) != ERR_OK) { - /* drop */ - pbuf_free(p); - pbuf_free(r); - ICMP6_STATS_INC(icmp6.err); - return; - } - - /* Determine reply source IPv6 address. */ -#if LWIP_MULTICAST_PING - if (ip6_addr_ismulticast(ip6_current_dest_addr())) { - reply_src = ip_2_ip6(ip6_select_source_address(inp, ip6_current_src_addr())); - if (reply_src == NULL) { - /* drop */ - pbuf_free(p); - pbuf_free(r); - ICMP6_STATS_INC(icmp6.rterr); - return; - } - } - else -#endif /* LWIP_MULTICAST_PING */ - { - reply_src = ip6_current_dest_addr(); - } - - /* Set fields in reply. */ - ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP; - ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0; -#if CHECKSUM_GEN_ICMP6 - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) { - ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, - IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr()); - } -#endif /* CHECKSUM_GEN_ICMP6 */ - - /* Send reply. */ - ICMP6_STATS_INC(icmp6.xmit); - ip6_output_if(r, reply_src, ip6_current_src_addr(), - LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp); - pbuf_free(r); - - break; - default: - ICMP6_STATS_INC(icmp6.proterr); - ICMP6_STATS_INC(icmp6.drop); - break; - } - - pbuf_free(p); -} - - -/** - * Send an icmpv6 'destination unreachable' packet. - * - * This function must be used only in direct response to a packet that is being - * received right now. Otherwise, address zones would be lost. - * - * @param p the input packet for which the 'unreachable' should be sent, - * p->payload pointing to the IPv6 header - * @param c ICMPv6 code for the unreachable type - */ -void -icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c) -{ - icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR); -} - -/** - * Send an icmpv6 'packet too big' packet. - * - * This function must be used only in direct response to a packet that is being - * received right now. Otherwise, address zones would be lost. - * - * @param p the input packet for which the 'packet too big' should be sent, - * p->payload pointing to the IPv6 header - * @param mtu the maximum mtu that we can accept - */ -void -icmp6_packet_too_big(struct pbuf *p, u32_t mtu) -{ - icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB); -} - -/** - * Send an icmpv6 'time exceeded' packet. - * - * This function must be used only in direct response to a packet that is being - * received right now. Otherwise, address zones would be lost. - * - * @param p the input packet for which the 'time exceeded' should be sent, - * p->payload pointing to the IPv6 header - * @param c ICMPv6 code for the time exceeded type - */ -void -icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c) -{ - icmp6_send_response(p, c, 0, ICMP6_TYPE_TE); -} - -/** - * Send an icmpv6 'time exceeded' packet, with explicit source and destination - * addresses. - * - * This function may be used to send a response sometime after receiving the - * packet for which this response is meant. The provided source and destination - * addresses are used primarily to retain their zone information. - * - * @param p the input packet for which the 'time exceeded' should be sent, - * p->payload pointing to the IPv6 header - * @param c ICMPv6 code for the time exceeded type - * @param src_addr source address of the original packet, with zone information - * @param dest_addr destination address of the original packet, with zone - * information - */ -void -icmp6_time_exceeded_with_addrs(struct pbuf *p, enum icmp6_te_code c, - const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr) -{ - icmp6_send_response_with_addrs(p, c, 0, ICMP6_TYPE_TE, src_addr, dest_addr); -} - -/** - * Send an icmpv6 'parameter problem' packet. - * - * This function must be used only in direct response to a packet that is being - * received right now. Otherwise, address zones would be lost and the calculated - * offset would be wrong (calculated against ip6_current_header()). - * - * @param p the input packet for which the 'param problem' should be sent, - * p->payload pointing to the IP header - * @param c ICMPv6 code for the param problem type - * @param pointer the pointer to the byte where the parameter is found - */ -void -icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, const void *pointer) -{ - u32_t pointer_u32 = (u32_t)((const u8_t *)pointer - (const u8_t *)ip6_current_header()); - icmp6_send_response(p, c, pointer_u32, ICMP6_TYPE_PP); -} - -/** - * Send an ICMPv6 packet in response to an incoming packet. - * The packet is sent *to* ip_current_src_addr() on ip_current_netif(). - * - * @param p the input packet for which the response should be sent, - * p->payload pointing to the IPv6 header - * @param code Code of the ICMPv6 header - * @param data Additional 32-bit parameter in the ICMPv6 header - * @param type Type of the ICMPv6 header - */ -static void -icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) -{ - const struct ip6_addr *reply_src, *reply_dest; - struct netif *netif = ip_current_netif(); - - LWIP_ASSERT("icmpv6 packet not a direct response", netif != NULL); - reply_dest = ip6_current_src_addr(); - - /* Select an address to use as source. */ - reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest)); - if (reply_src == NULL) { - ICMP6_STATS_INC(icmp6.rterr); - return; - } - icmp6_send_response_with_addrs_and_netif(p, code, data, type, reply_src, reply_dest, netif); -} - -/** - * Send an ICMPv6 packet in response to an incoming packet. - * - * Call this function if the packet is NOT sent as a direct response to an - * incoming packet, but rather sometime later (e.g. for a fragment reassembly - * timeout). The caller must provide the zoned source and destination addresses - * from the original packet with the src_addr and dest_addr parameters. The - * reason for this approach is that while the addresses themselves are part of - * the original packet, their zone information is not, thus possibly resulting - * in a link-local response being sent over the wrong link. - * - * @param p the input packet for which the response should be sent, - * p->payload pointing to the IPv6 header - * @param code Code of the ICMPv6 header - * @param data Additional 32-bit parameter in the ICMPv6 header - * @param type Type of the ICMPv6 header - * @param src_addr original source address - * @param dest_addr original destination address - */ -static void -icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data, u8_t type, - const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr) -{ - const struct ip6_addr *reply_src, *reply_dest; - struct netif *netif; - - /* Get the destination address and netif for this ICMP message. */ - LWIP_ASSERT("must provide both source and destination", src_addr != NULL); - LWIP_ASSERT("must provide both source and destination", dest_addr != NULL); - - /* Special case, as ip6_current_xxx is either NULL, or points - to a different packet than the one that expired. */ - IP6_ADDR_ZONECHECK(src_addr); - IP6_ADDR_ZONECHECK(dest_addr); - /* Swap source and destination for the reply. */ - reply_dest = src_addr; - reply_src = dest_addr; - netif = ip6_route(reply_src, reply_dest); - if (netif == NULL) { - ICMP6_STATS_INC(icmp6.rterr); - return; - } - icmp6_send_response_with_addrs_and_netif(p, code, data, type, reply_src, - reply_dest, netif); -} - -/** - * Send an ICMPv6 packet (with srd/dst address and netif given). - * - * @param p the input packet for which the response should be sent, - * p->payload pointing to the IPv6 header - * @param code Code of the ICMPv6 header - * @param data Additional 32-bit parameter in the ICMPv6 header - * @param type Type of the ICMPv6 header - * @param reply_src source address of the packet to send - * @param reply_dest destination address of the packet to send - * @param netif netif to send the packet - */ -static void -icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data, u8_t type, - const ip6_addr_t *reply_src, const ip6_addr_t *reply_dest, struct netif *netif) -{ - struct pbuf *q; - struct icmp6_hdr *icmp6hdr; - - /* ICMPv6 header + IPv6 header + data */ - q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE, - PBUF_RAM); - if (q == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n")); - ICMP6_STATS_INC(icmp6.memerr); - return; - } - LWIP_ASSERT("check that first pbuf can hold icmp 6message", - (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE))); - - icmp6hdr = (struct icmp6_hdr *)q->payload; - icmp6hdr->type = type; - icmp6hdr->code = code; - icmp6hdr->data = lwip_htonl(data); - - /* copy fields from original packet */ - SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload, - IP6_HLEN + LWIP_ICMP6_DATASIZE); - - /* calculate checksum */ - icmp6hdr->chksum = 0; -#if CHECKSUM_GEN_ICMP6 - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { - icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, - reply_src, reply_dest); - } -#endif /* CHECKSUM_GEN_ICMP6 */ - - ICMP6_STATS_INC(icmp6.xmit); - ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); - pbuf_free(q); -} - -#endif /* LWIP_ICMP6 && LWIP_IPV6 */ diff --git a/core/c/core/ipv6/inet6.c b/core/c/core/ipv6/inet6.c deleted file mode 100755 index 7cb16aa..0000000 --- a/core/c/core/ipv6/inet6.c +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @file - * - * INET v6 addresses. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#include "lwip/opt.h" - -#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/def.h" -#include "lwip/inet.h" - -/** This variable is initialized by the system to contain the wildcard IPv6 address. - */ -const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; - -#endif /* LWIP_IPV6 */ diff --git a/core/c/core/ipv6/ip6.c b/core/c/core/ipv6/ip6.c deleted file mode 100755 index 0ede432..0000000 --- a/core/c/core/ipv6/ip6.c +++ /dev/null @@ -1,1505 +0,0 @@ -/** - * @file - * - * IPv6 layer. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#include "lwip/opt.h" - -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/netif.h" -#include "lwip/ip.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/ip6_frag.h" -#include "lwip/icmp6.h" -#include "lwip/priv/raw_priv.h" -#include "lwip/udp.h" -#include "lwip/priv/tcp_priv.h" -#include "lwip/dhcp6.h" -#include "lwip/nd6.h" -#include "lwip/mld6.h" -#include "lwip/debug.h" -#include "lwip/stats.h" - -#ifdef LWIP_HOOK_FILENAME -#include LWIP_HOOK_FILENAME -#endif - -/** - * Finds the appropriate network interface for a given IPv6 address. It tries to select - * a netif following a sequence of heuristics: - * 1) if there is only 1 netif, return it - * 2) if the destination is a zoned address, match its zone to a netif - * 3) if the either the source or destination address is a scoped address, - * match the source address's zone (if set) or address (if not) to a netif - * 4) tries to match the destination subnet to a configured address - * 5) tries to find a router-announced route - * 6) tries to match the (unscoped) source address to the netif - * 7) returns the default netif, if configured - * - * Note that each of the two given addresses may or may not be properly zoned. - * - * @param src the source IPv6 address, if known - * @param dest the destination IPv6 address for which to find the route - * @return the netif on which to send to reach dest - */ -struct netif * -ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) -{ -#if TUN2SOCKS - // go-tun2socks logic - // no routing and just use the default netif, netif_list[0], i.e., the loopif - // enable loopif by setting LWIP_HAVE_LOOPIF = 1 in lwipopts.h - return netif_list; -#endif /* TUN2SOCKS */ - -#if LWIP_SINGLE_NETIF - LWIP_UNUSED_ARG(src); - LWIP_UNUSED_ARG(dest); -#else /* LWIP_SINGLE_NETIF */ - struct netif *netif; - s8_t i; - - LWIP_ASSERT_CORE_LOCKED(); - - /* If single netif configuration, fast return. */ - if ((netif_list != NULL) && (netif_list->next == NULL)) { - if (!netif_is_up(netif_list) || !netif_is_link_up(netif_list) || - (ip6_addr_has_zone(dest) && !ip6_addr_test_zone(dest, netif_list))) { - return NULL; - } - return netif_list; - } - -#if LWIP_IPV6_SCOPES - /* Special processing for zoned destination addresses. This includes link- - * local unicast addresses and interface/link-local multicast addresses. Use - * the zone to find a matching netif. If the address is not zoned, then there - * is technically no "wrong" netif to choose, and we leave routing to other - * rules; in most cases this should be the scoped-source rule below. */ - if (ip6_addr_has_zone(dest)) { - IP6_ADDR_ZONECHECK(dest); - /* Find a netif based on the zone. For custom mappings, one zone may map - * to multiple netifs, so find one that can actually send a packet. */ - NETIF_FOREACH(netif) { - if (ip6_addr_test_zone(dest, netif) && - netif_is_up(netif) && netif_is_link_up(netif)) { - return netif; - } - } - /* No matching netif found. Do no try to route to a different netif, - * as that would be a zone violation, resulting in any packets sent to - * that netif being dropped on output. */ - return NULL; - } -#endif /* LWIP_IPV6_SCOPES */ - - /* Special processing for scoped source and destination addresses. If we get - * here, the destination address does not have a zone, so either way we need - * to look at the source address, which may or may not have a zone. If it - * does, the zone is restrictive: there is (typically) only one matching - * netif for it, and we should avoid routing to any other netif as that would - * result in guaranteed zone violations. For scoped source addresses that do - * not have a zone, use (only) a netif that has that source address locally - * assigned. This case also applies to the loopback source address, which has - * an implied link-local scope. If only the destination address is scoped - * (but, again, not zoned), we still want to use only the source address to - * determine its zone because that's most likely what the user/application - * wants, regardless of whether the source address is scoped. Finally, some - * of this story also applies if scoping is disabled altogether. */ -#if LWIP_IPV6_SCOPES - if (ip6_addr_has_scope(dest, IP6_UNKNOWN) || - ip6_addr_has_scope(src, IP6_UNICAST) || -#else /* LWIP_IPV6_SCOPES */ - if (ip6_addr_islinklocal(dest) || ip6_addr_ismulticast_iflocal(dest) || - ip6_addr_ismulticast_linklocal(dest) || ip6_addr_islinklocal(src) || -#endif /* LWIP_IPV6_SCOPES */ - ip6_addr_isloopback(src)) { -#if LWIP_IPV6_SCOPES - if (ip6_addr_has_zone(src)) { - /* Find a netif matching the source zone (relatively cheap). */ - NETIF_FOREACH(netif) { - if (netif_is_up(netif) && netif_is_link_up(netif) && - ip6_addr_test_zone(src, netif)) { - return netif; - } - } - } else -#endif /* LWIP_IPV6_SCOPES */ - { - /* Find a netif matching the source address (relatively expensive). */ - NETIF_FOREACH(netif) { - if (!netif_is_up(netif) || !netif_is_link_up(netif)) { - continue; - } - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_cmp_zoneless(src, netif_ip6_addr(netif, i))) { - return netif; - } - } - } - } - /* Again, do not use any other netif in this case, as that could result in - * zone boundary violations. */ - return NULL; - } - - /* We come here only if neither source nor destination is scoped. */ - IP6_ADDR_ZONECHECK(src); - -#ifdef LWIP_HOOK_IP6_ROUTE - netif = LWIP_HOOK_IP6_ROUTE(src, dest); - if (netif != NULL) { - return netif; - } -#endif - - /* See if the destination subnet matches a configured address. In accordance - * with RFC 5942, dynamically configured addresses do not have an implied - * local subnet, and thus should be considered /128 assignments. However, as - * such, the destination address may still match a local address, and so we - * still need to check for exact matches here. By (lwIP) policy, statically - * configured addresses do always have an implied local /64 subnet. */ - NETIF_FOREACH(netif) { - if (!netif_is_up(netif) || !netif_is_link_up(netif)) { - continue; - } - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_netcmp(dest, netif_ip6_addr(netif, i)) && - (netif_ip6_addr_isstatic(netif, i) || - ip6_addr_nethostcmp(dest, netif_ip6_addr(netif, i)))) { - return netif; - } - } - } - - /* Get the netif for a suitable router-announced route. */ - netif = nd6_find_route(dest); - if (netif != NULL) { - return netif; - } - - /* Try with the netif that matches the source address. Given the earlier rule - * for scoped source addresses, this applies to unscoped addresses only. */ - if (!ip6_addr_isany(src)) { - NETIF_FOREACH(netif) { - if (!netif_is_up(netif) || !netif_is_link_up(netif)) { - continue; - } - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_cmp(src, netif_ip6_addr(netif, i))) { - return netif; - } - } - } - } - -#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF - /* loopif is disabled, loopback traffic is passed through any netif */ - if (ip6_addr_isloopback(dest)) { - /* don't check for link on loopback traffic */ - if (netif_default != NULL && netif_is_up(netif_default)) { - return netif_default; - } - /* default netif is not up, just use any netif for loopback traffic */ - NETIF_FOREACH(netif) { - if (netif_is_up(netif)) { - return netif; - } - } - return NULL; - } -#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */ -#endif /* !LWIP_SINGLE_NETIF */ - - /* no matching netif found, use default netif, if up */ - if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default)) { - return NULL; - } - return netif_default; -} - -/** - * @ingroup ip6 - * Select the best IPv6 source address for a given destination IPv6 address. - * - * This implementation follows RFC 6724 Sec. 5 to the following extent: - * - Rules 1, 2, 3: fully implemented - * - Rules 4, 5, 5.5: not applicable - * - Rule 6: not implemented - * - Rule 7: not applicable - * - Rule 8: limited to "prefer /64 subnet match over non-match" - * - * For Rule 2, we deliberately deviate from RFC 6724 Sec. 3.1 by considering - * ULAs to be of smaller scope than global addresses, to avoid that a preferred - * ULA is picked over a deprecated global address when given a global address - * as destination, as that would likely result in broken two-way communication. - * - * As long as temporary addresses are not supported (as used in Rule 7), a - * proper implementation of Rule 8 would obviate the need to implement Rule 6. - * - * @param netif the netif on which to send a packet - * @param dest the destination we are trying to reach (possibly not properly - * zoned) - * @return the most suitable source address to use, or NULL if no suitable - * source address is found - */ -const ip_addr_t * -ip6_select_source_address(struct netif *netif, const ip6_addr_t *dest) -{ - const ip_addr_t *best_addr; - const ip6_addr_t *cand_addr; - s8_t dest_scope, cand_scope; - s8_t best_scope = IP6_MULTICAST_SCOPE_RESERVED; - u8_t i, cand_pref, cand_bits; - u8_t best_pref = 0; - u8_t best_bits = 0; - - /* Start by determining the scope of the given destination address. These - * tests are hopefully (roughly) in order of likeliness to match. */ - if (ip6_addr_isglobal(dest)) { - dest_scope = IP6_MULTICAST_SCOPE_GLOBAL; - } else if (ip6_addr_islinklocal(dest) || ip6_addr_isloopback(dest)) { - dest_scope = IP6_MULTICAST_SCOPE_LINK_LOCAL; - } else if (ip6_addr_isuniquelocal(dest)) { - dest_scope = IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL; - } else if (ip6_addr_ismulticast(dest)) { - dest_scope = ip6_addr_multicast_scope(dest); - } else if (ip6_addr_issitelocal(dest)) { - dest_scope = IP6_MULTICAST_SCOPE_SITE_LOCAL; - } else { - /* no match, consider scope global */ - dest_scope = IP6_MULTICAST_SCOPE_GLOBAL; - } - - best_addr = NULL; - - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - /* Consider only valid (= preferred and deprecated) addresses. */ - if (!ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) { - continue; - } - /* Determine the scope of this candidate address. Same ordering idea. */ - cand_addr = netif_ip6_addr(netif, i); - if (ip6_addr_isglobal(cand_addr)) { - cand_scope = IP6_MULTICAST_SCOPE_GLOBAL; - } else if (ip6_addr_islinklocal(cand_addr)) { - cand_scope = IP6_MULTICAST_SCOPE_LINK_LOCAL; - } else if (ip6_addr_isuniquelocal(cand_addr)) { - cand_scope = IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL; - } else if (ip6_addr_issitelocal(cand_addr)) { - cand_scope = IP6_MULTICAST_SCOPE_SITE_LOCAL; - } else { - /* no match, treat as low-priority global scope */ - cand_scope = IP6_MULTICAST_SCOPE_RESERVEDF; - } - cand_pref = ip6_addr_ispreferred(netif_ip6_addr_state(netif, i)); - /* @todo compute the actual common bits, for longest matching prefix. */ - /* We cannot count on the destination address having a proper zone - * assignment, so do not compare zones in this case. */ - cand_bits = ip6_addr_netcmp_zoneless(cand_addr, dest); /* just 1 or 0 for now */ - if (cand_bits && ip6_addr_nethostcmp(cand_addr, dest)) { - return netif_ip_addr6(netif, i); /* Rule 1 */ - } - if ((best_addr == NULL) || /* no alternative yet */ - ((cand_scope < best_scope) && (cand_scope >= dest_scope)) || - ((cand_scope > best_scope) && (best_scope < dest_scope)) || /* Rule 2 */ - ((cand_scope == best_scope) && ((cand_pref > best_pref) || /* Rule 3 */ - ((cand_pref == best_pref) && (cand_bits > best_bits))))) { /* Rule 8 */ - /* We found a new "winning" candidate. */ - best_addr = netif_ip_addr6(netif, i); - best_scope = cand_scope; - best_pref = cand_pref; - best_bits = cand_bits; - } - } - - return best_addr; /* may be NULL */ -} - -#if LWIP_IPV6_FORWARD -/** - * Forwards an IPv6 packet. It finds an appropriate route for the - * packet, decrements the HL value of the packet, and outputs - * the packet on the appropriate interface. - * - * @param p the packet to forward (p->payload points to IP header) - * @param iphdr the IPv6 header of the input packet - * @param inp the netif on which this packet was received - */ -static void -ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp) -{ - struct netif *netif; - - /* do not forward link-local or loopback addresses */ - if (ip6_addr_islinklocal(ip6_current_dest_addr()) || - ip6_addr_isloopback(ip6_current_dest_addr())) { - LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n")); - IP6_STATS_INC(ip6.rterr); - IP6_STATS_INC(ip6.drop); - return; - } - - /* Find network interface where to forward this IP packet to. */ - netif = ip6_route(IP6_ADDR_ANY6, ip6_current_dest_addr()); - if (netif == NULL) { - LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", - IP6_ADDR_BLOCK1(ip6_current_dest_addr()), - IP6_ADDR_BLOCK2(ip6_current_dest_addr()), - IP6_ADDR_BLOCK3(ip6_current_dest_addr()), - IP6_ADDR_BLOCK4(ip6_current_dest_addr()), - IP6_ADDR_BLOCK5(ip6_current_dest_addr()), - IP6_ADDR_BLOCK6(ip6_current_dest_addr()), - IP6_ADDR_BLOCK7(ip6_current_dest_addr()), - IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); -#if LWIP_ICMP6 - /* Don't send ICMP messages in response to ICMP messages */ - if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { - icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE); - } -#endif /* LWIP_ICMP6 */ - IP6_STATS_INC(ip6.rterr); - IP6_STATS_INC(ip6.drop); - return; - } -#if LWIP_IPV6_SCOPES - /* Do not forward packets with a zoned (e.g., link-local) source address - * outside of their zone. We determined the zone a bit earlier, so we know - * that the address is properly zoned here, so we can safely use has_zone. - * Also skip packets with a loopback source address (link-local implied). */ - if ((ip6_addr_has_zone(ip6_current_src_addr()) && - !ip6_addr_test_zone(ip6_current_src_addr(), netif)) || - ip6_addr_isloopback(ip6_current_src_addr())) { - LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding packet beyond its source address zone.\n")); - IP6_STATS_INC(ip6.rterr); - IP6_STATS_INC(ip6.drop); - return; - } -#endif /* LWIP_IPV6_SCOPES */ - /* Do not forward packets onto the same network interface on which - * they arrived. */ - if (netif == inp) { - LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n")); - IP6_STATS_INC(ip6.rterr); - IP6_STATS_INC(ip6.drop); - return; - } - - /* decrement HL */ - IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1); - /* send ICMP6 if HL == 0 */ - if (IP6H_HOPLIM(iphdr) == 0) { -#if LWIP_ICMP6 - /* Don't send ICMP messages in response to ICMP messages */ - if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { - icmp6_time_exceeded(p, ICMP6_TE_HL); - } -#endif /* LWIP_ICMP6 */ - IP6_STATS_INC(ip6.drop); - return; - } - - if (netif->mtu && (p->tot_len > netif->mtu)) { -#if LWIP_ICMP6 - /* Don't send ICMP messages in response to ICMP messages */ - if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { - icmp6_packet_too_big(p, netif->mtu); - } -#endif /* LWIP_ICMP6 */ - IP6_STATS_INC(ip6.drop); - return; - } - - LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: forwarding packet to %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", - IP6_ADDR_BLOCK1(ip6_current_dest_addr()), - IP6_ADDR_BLOCK2(ip6_current_dest_addr()), - IP6_ADDR_BLOCK3(ip6_current_dest_addr()), - IP6_ADDR_BLOCK4(ip6_current_dest_addr()), - IP6_ADDR_BLOCK5(ip6_current_dest_addr()), - IP6_ADDR_BLOCK6(ip6_current_dest_addr()), - IP6_ADDR_BLOCK7(ip6_current_dest_addr()), - IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); - - /* transmit pbuf on chosen interface */ - netif->output_ip6(netif, p, ip6_current_dest_addr()); - IP6_STATS_INC(ip6.fw); - IP6_STATS_INC(ip6.xmit); - return; -} -#endif /* LWIP_IPV6_FORWARD */ - -/** Return true if the current input packet should be accepted on this netif */ -static int -ip6_input_accept(struct netif *netif) -{ -#if TUN2SOCKS - // go-tun2socks logic - // all packets are accepted by the first one, and it should be the loopif - return 1; -#endif /* TUN2SOCKS */ - - /* interface is up? */ - if (netif_is_up(netif)) { - u8_t i; - /* unicast to this interface address? address configured? */ - /* If custom scopes are used, the destination zone will be tested as - * part of the local-address comparison, but we need to test the source - * scope as well (e.g., is this interface on the same link?). */ - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(netif, i)) -#if IPV6_CUSTOM_SCOPES - && (!ip6_addr_has_zone(ip6_current_src_addr()) || - ip6_addr_test_zone(ip6_current_src_addr(), netif)) -#endif /* IPV6_CUSTOM_SCOPES */ - ) { - /* accept on this netif */ - return 1; - } - } - } - return 0; -} - -/** - * This function is called by the network interface device driver when - * an IPv6 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 ip6_forward). - * - * Finally, the packet is sent to the upper layer protocol input function. - * - * @param p the received IPv6 packet (p->payload points to IPv6 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 -ip6_input(struct pbuf *p, struct netif *inp) -{ - struct ip6_hdr *ip6hdr; - struct netif *netif; - const u8_t *nexth; - u16_t hlen, hlen_tot; /* the current header length */ -#if 0 /*IP_ACCEPT_LINK_LAYER_ADDRESSING*/ - @todo - int check_ip_src=1; -#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ -#if LWIP_RAW - raw_input_state_t raw_status; -#endif /* LWIP_RAW */ - - LWIP_ASSERT_CORE_LOCKED(); - - IP6_STATS_INC(ip6.recv); - - /* identify the IP header */ - ip6hdr = (struct ip6_hdr *)p->payload; - if (IP6H_V(ip6hdr) != 6) { - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IPv6 packet dropped due to bad version number %"U32_F"\n", - IP6H_V(ip6hdr))); - pbuf_free(p); - IP6_STATS_INC(ip6.err); - IP6_STATS_INC(ip6.drop); - return ERR_OK; - } - -#ifdef LWIP_HOOK_IP6_INPUT - if (LWIP_HOOK_IP6_INPUT(p, inp)) { - /* the packet has been eaten */ - return ERR_OK; - } -#endif - - /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ - if ((IP6_HLEN > p->len) || (IP6H_PLEN(ip6hdr) > (p->tot_len - IP6_HLEN))) { - if (IP6_HLEN > p->len) { - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("IPv6 header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", - (u16_t)IP6_HLEN, p->len)); - } - if ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len) { - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("IPv6 (plen %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", - (u16_t)(IP6H_PLEN(ip6hdr) + IP6_HLEN), p->tot_len)); - } - /* free (drop) packet pbufs */ - pbuf_free(p); - IP6_STATS_INC(ip6.lenerr); - IP6_STATS_INC(ip6.drop); - return ERR_OK; - } - - /* 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, (u16_t)(IP6_HLEN + IP6H_PLEN(ip6hdr))); - - /* copy IP addresses to aligned ip6_addr_t */ - ip_addr_copy_from_ip6_packed(ip_data.current_iphdr_dest, ip6hdr->dest); - ip_addr_copy_from_ip6_packed(ip_data.current_iphdr_src, ip6hdr->src); - - /* Don't accept virtual IPv4 mapped IPv6 addresses. - * Don't accept multicast source addresses. */ - if (ip6_addr_isipv4mappedipv6(ip_2_ip6(&ip_data.current_iphdr_dest)) || - ip6_addr_isipv4mappedipv6(ip_2_ip6(&ip_data.current_iphdr_src)) || - ip6_addr_ismulticast(ip_2_ip6(&ip_data.current_iphdr_src))) { - /* free (drop) packet pbufs */ - pbuf_free(p); - IP6_STATS_INC(ip6.err); - IP6_STATS_INC(ip6.drop); - return ERR_OK; - } - - /* Set the appropriate zone identifier on the addresses. */ - ip6_addr_assign_zone(ip_2_ip6(&ip_data.current_iphdr_dest), IP6_UNKNOWN, inp); - ip6_addr_assign_zone(ip_2_ip6(&ip_data.current_iphdr_src), IP6_UNICAST, inp); - - /* current header pointer. */ - ip_data.current_ip6_header = ip6hdr; - - /* In netif, used in case we need to send ICMPv6 packets back. */ - ip_data.current_netif = inp; - ip_data.current_input_netif = inp; - - /* match packet against an interface, i.e. is this packet for us? */ - if (ip6_addr_ismulticast(ip6_current_dest_addr())) { - /* Always joined to multicast if-local and link-local all-nodes group. */ - if (ip6_addr_isallnodes_iflocal(ip6_current_dest_addr()) || - ip6_addr_isallnodes_linklocal(ip6_current_dest_addr())) { - netif = inp; - } -#if LWIP_IPV6_MLD - else if (mld6_lookfor_group(inp, ip6_current_dest_addr())) { - netif = inp; - } -#else /* LWIP_IPV6_MLD */ - else if (ip6_addr_issolicitednode(ip6_current_dest_addr())) { - u8_t i; - /* Filter solicited node packets when MLD is not enabled - * (for Neighbor discovery). */ - netif = NULL; - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) && - ip6_addr_cmp_solicitednode(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { - netif = inp; - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: solicited node packet accepted on interface %c%c\n", - netif->name[0], netif->name[1])); - break; - } - } - } -#endif /* LWIP_IPV6_MLD */ - else { - netif = NULL; - } - } else { - /* start trying with inp. if that's not acceptable, start walking the - list of configured netifs. */ - if (ip6_input_accept(inp)) { - netif = inp; - } else { - netif = NULL; -#if !IPV6_CUSTOM_SCOPES - /* Shortcut: stop looking for other interfaces if either the source or - * the destination has a scope constrained to this interface. Custom - * scopes may break the 1:1 link/interface mapping, however. */ - if (ip6_addr_islinklocal(ip6_current_dest_addr()) || - ip6_addr_islinklocal(ip6_current_src_addr())) { - goto netif_found; - } -#endif /* !IPV6_CUSTOM_SCOPES */ -#if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF - /* The loopback address is to be considered link-local. Packets to it - * should be dropped on other interfaces, as per RFC 4291 Sec. 2.5.3. - * Its implied scope means packets *from* the loopback address should - * not be accepted on other interfaces, either. These requirements - * cannot be implemented in the case that loopback traffic is sent - * across a non-loopback interface, however. */ - if (ip6_addr_isloopback(ip6_current_dest_addr()) || - ip6_addr_isloopback(ip6_current_src_addr())) { - goto netif_found; - } -#endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */ -#if !LWIP_SINGLE_NETIF - NETIF_FOREACH(netif) { - if (netif == inp) { - /* we checked that before already */ - continue; - } - if (ip6_input_accept(netif)) { - break; - } - } -#endif /* !LWIP_SINGLE_NETIF */ - } -netif_found: - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet accepted on interface %c%c\n", - netif ? netif->name[0] : 'X', netif? netif->name[1] : 'X')); - } - - /* "::" packet source address? (used in duplicate address detection) */ - if (ip6_addr_isany(ip6_current_src_addr()) && - (!ip6_addr_issolicitednode(ip6_current_dest_addr()))) { - /* packet source is not valid */ - /* free (drop) packet pbufs */ - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with src ANY_ADDRESS dropped\n")); - pbuf_free(p); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - } - - /* packet not for us? */ - if (netif == NULL) { - /* packet not for us, route or discard */ - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_TRACE, ("ip6_input: packet not for us.\n")); -#if LWIP_IPV6_FORWARD - /* non-multicast packet? */ - if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { - /* try to forward IP packet on (other) interfaces */ - ip6_forward(p, ip6hdr, inp); - } -#endif /* LWIP_IPV6_FORWARD */ - pbuf_free(p); - goto ip6_input_cleanup; - } - - /* current netif pointer. */ - ip_data.current_netif = netif; - - /* Save next header type. */ - nexth = &IP6H_NEXTH(ip6hdr); - - /* Init header length. */ - hlen = hlen_tot = IP6_HLEN; - - /* Move to payload. */ - pbuf_remove_header(p, IP6_HLEN); - - /* Process known option extension headers, if present. */ - while (*nexth != IP6_NEXTH_NONE) - { - switch (*nexth) { - case IP6_NEXTH_HOPBYHOP: - { - s32_t opt_offset; - struct ip6_hbh_hdr *hbh_hdr; - struct ip6_opt_hdr *opt_hdr; - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header\n")); - - /* Get and check the header length, while staying in packet bounds. */ - hbh_hdr = (struct ip6_hbh_hdr *)p->payload; - - /* Get next header type. */ - nexth = &IP6_HBH_NEXTH(hbh_hdr); - - /* Get the header length. */ - hlen = (u16_t)(8 * (1 + hbh_hdr->_hlen)); - - if ((p->len < 8) || (hlen > p->len)) { - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", - hlen, p->len)); - /* free (drop) packet pbufs */ - pbuf_free(p); - IP6_STATS_INC(ip6.lenerr); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - } - - hlen_tot = (u16_t)(hlen_tot + hlen); - - /* The extended option header starts right after Hop-by-Hop header. */ - opt_offset = IP6_HBH_HLEN; - while (opt_offset < hlen) - { - s32_t opt_dlen = 0; - - opt_hdr = (struct ip6_opt_hdr *)((u8_t *)hbh_hdr + opt_offset); - - switch (IP6_OPT_TYPE(opt_hdr)) { - /* @todo: process IPV6 Hop-by-Hop option data */ - case IP6_PAD1_OPTION: - /* PAD1 option doesn't have length and value field */ - opt_dlen = -1; - break; - case IP6_PADN_OPTION: - opt_dlen = IP6_OPT_DLEN(opt_hdr); - break; - case IP6_ROUTER_ALERT_OPTION: - opt_dlen = IP6_OPT_DLEN(opt_hdr); - break; - case IP6_JUMBO_OPTION: - opt_dlen = IP6_OPT_DLEN(opt_hdr); - break; - default: - /* Check 2 MSB of Hop-by-Hop header type. */ - switch (IP6_OPT_TYPE_ACTION(opt_hdr)) { - case 1: - /* Discard the packet. */ - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid Hop-by-Hop option type dropped.\n")); - pbuf_free(p); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - case 2: - /* Send ICMP Parameter Problem */ - icmp6_param_problem(p, ICMP6_PP_OPTION, opt_hdr); - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid Hop-by-Hop option type dropped.\n")); - pbuf_free(p); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - case 3: - /* Send ICMP Parameter Problem if destination address is not a multicast address */ - if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { - icmp6_param_problem(p, ICMP6_PP_OPTION, opt_hdr); - } - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid Hop-by-Hop option type dropped.\n")); - pbuf_free(p); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - default: - /* Skip over this option. */ - opt_dlen = IP6_OPT_DLEN(opt_hdr); - break; - } - break; - } - - /* Adjust the offset to move to the next extended option header */ - opt_offset = opt_offset + IP6_OPT_HLEN + opt_dlen; - } - pbuf_remove_header(p, hlen); - break; - } - case IP6_NEXTH_DESTOPTS: - { - s32_t opt_offset; - struct ip6_dest_hdr *dest_hdr; - struct ip6_opt_hdr *opt_hdr; - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Destination options header\n")); - - dest_hdr = (struct ip6_dest_hdr *)p->payload; - - /* Get next header type. */ - nexth = &IP6_DEST_NEXTH(dest_hdr); - - /* Get the header length. */ - hlen = 8 * (1 + dest_hdr->_hlen); - if ((p->len < 8) || (hlen > p->len)) { - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", - hlen, p->len)); - /* free (drop) packet pbufs */ - pbuf_free(p); - IP6_STATS_INC(ip6.lenerr); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - } - - hlen_tot = (u16_t)(hlen_tot + hlen); - - /* The extended option header starts right after Destination header. */ - opt_offset = IP6_DEST_HLEN; - while (opt_offset < hlen) - { - s32_t opt_dlen = 0; - - opt_hdr = (struct ip6_opt_hdr *)((u8_t *)dest_hdr + opt_offset); - - switch (IP6_OPT_TYPE(opt_hdr)) - { - /* @todo: process IPV6 Destination option data */ - case IP6_PAD1_OPTION: - /* PAD1 option deosn't have length and value field */ - opt_dlen = -1; - break; - case IP6_PADN_OPTION: - opt_dlen = IP6_OPT_DLEN(opt_hdr); - break; - case IP6_ROUTER_ALERT_OPTION: - opt_dlen = IP6_OPT_DLEN(opt_hdr); - break; - case IP6_JUMBO_OPTION: - opt_dlen = IP6_OPT_DLEN(opt_hdr); - break; - case IP6_HOME_ADDRESS_OPTION: - opt_dlen = IP6_OPT_DLEN(opt_hdr); - break; - default: - /* Check 2 MSB of Destination header type. */ - switch (IP6_OPT_TYPE_ACTION(opt_hdr)) - { - case 1: - /* Discard the packet. */ - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid destination option type dropped.\n")); - pbuf_free(p); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - case 2: - /* Send ICMP Parameter Problem */ - icmp6_param_problem(p, ICMP6_PP_OPTION, opt_hdr); - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid destination option type dropped.\n")); - pbuf_free(p); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - case 3: - /* Send ICMP Parameter Problem if destination address is not a multicast address */ - if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { - icmp6_param_problem(p, ICMP6_PP_OPTION, opt_hdr); - } - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid destination option type dropped.\n")); - pbuf_free(p); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - default: - /* Skip over this option. */ - opt_dlen = IP6_OPT_DLEN(opt_hdr); - break; - } - break; - } - - /* Adjust the offset to move to the next extended option header */ - opt_offset = opt_offset + IP6_OPT_HLEN + opt_dlen; - } - - pbuf_remove_header(p, hlen); - break; - } - case IP6_NEXTH_ROUTING: - { - struct ip6_rout_hdr *rout_hdr; - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Routing header\n")); - - rout_hdr = (struct ip6_rout_hdr *)p->payload; - - /* Get next header type. */ - nexth = &IP6_ROUT_NEXTH(rout_hdr); - - /* Get the header length. */ - hlen = 8 * (1 + rout_hdr->_hlen); - - if ((p->len < 8) || (hlen > p->len)) { - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", - hlen, p->len)); - /* free (drop) packet pbufs */ - pbuf_free(p); - IP6_STATS_INC(ip6.lenerr); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - } - - /* Skip over this header. */ - hlen_tot = (u16_t)(hlen_tot + hlen); - - /* if segment left value is 0 in routing header, ignore the option */ - if (IP6_ROUT_SEG_LEFT(rout_hdr)) { - /* The length field of routing option header must be even */ - if (rout_hdr->_hlen & 0x1) { - /* Discard and send parameter field error */ - icmp6_param_problem(p, ICMP6_PP_FIELD, &rout_hdr->_hlen); - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid routing type dropped\n")); - pbuf_free(p); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - } - - switch (IP6_ROUT_TYPE(rout_hdr)) - { - /* TODO: process routing by the type */ - case IP6_ROUT_TYPE2: - break; - case IP6_ROUT_RPL: - break; - default: - /* Discard unrecognized routing type and send parameter field error */ - icmp6_param_problem(p, ICMP6_PP_FIELD, &IP6_ROUT_TYPE(rout_hdr)); - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid routing type dropped\n")); - pbuf_free(p); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - } - } - - pbuf_remove_header(p, hlen); - break; - } - case IP6_NEXTH_FRAGMENT: - { - struct ip6_frag_hdr *frag_hdr; - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header\n")); - - frag_hdr = (struct ip6_frag_hdr *)p->payload; - - /* Get next header type. */ - nexth = &IP6_FRAG_NEXTH(frag_hdr); - - /* Fragment Header length. */ - hlen = 8; - - /* Make sure this header fits in current pbuf. */ - if (hlen > p->len) { - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", - hlen, p->len)); - /* free (drop) packet pbufs */ - pbuf_free(p); - IP6_FRAG_STATS_INC(ip6_frag.lenerr); - IP6_FRAG_STATS_INC(ip6_frag.drop); - goto ip6_input_cleanup; - } - - hlen_tot = (u16_t)(hlen_tot + hlen); - - /* check payload length is multiple of 8 octets when mbit is set */ - if (IP6_FRAG_MBIT(frag_hdr) && (IP6H_PLEN(ip6hdr) & 0x7)) { - /* ipv6 payload length is not multiple of 8 octets */ - icmp6_param_problem(p, ICMP6_PP_FIELD, LWIP_PACKED_CAST(const void *, &ip6hdr->_plen)); - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid payload length dropped\n")); - pbuf_free(p); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - } - - /* Offset == 0 and more_fragments == 0? */ - if ((frag_hdr->_fragment_offset & - PP_HTONS(IP6_FRAG_OFFSET_MASK | IP6_FRAG_MORE_FLAG)) == 0) { - /* This is a 1-fragment packet. Skip this header and continue. */ - pbuf_remove_header(p, hlen); - } else { -#if LWIP_IPV6_REASS - /* reassemble the packet */ - ip_data.current_ip_header_tot_len = hlen_tot; - p = ip6_reass(p); - /* packet not fully reassembled yet? */ - if (p == NULL) { - goto ip6_input_cleanup; - } - - /* Returned p point to IPv6 header. - * Update all our variables and pointers and continue. */ - ip6hdr = (struct ip6_hdr *)p->payload; - nexth = &IP6H_NEXTH(ip6hdr); - hlen = hlen_tot = IP6_HLEN; - pbuf_remove_header(p, IP6_HLEN); - -#else /* LWIP_IPV6_REASS */ - /* free (drop) packet pbufs */ - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header dropped (with LWIP_IPV6_REASS==0)\n")); - pbuf_free(p); - IP6_STATS_INC(ip6.opterr); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; -#endif /* LWIP_IPV6_REASS */ - } - break; - } - default: - goto options_done; - } - - if (*nexth == IP6_NEXTH_HOPBYHOP) { - /* Hop-by-Hop header comes only as a first option */ - icmp6_param_problem(p, ICMP6_PP_HEADER, nexth); - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header dropped (only valid as a first option)\n")); - pbuf_free(p); - IP6_STATS_INC(ip6.drop); - goto ip6_input_cleanup; - } - } - -options_done: - - /* send to upper layers */ - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n")); - ip6_debug_print(p); - LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); - - ip_data.current_ip_header_tot_len = hlen_tot; - -#if LWIP_RAW - /* p points to IPv6 header again for raw_input. */ - pbuf_add_header_force(p, hlen_tot); - /* raw input did not eat the packet? */ - raw_status = raw_input(p, inp); - if (raw_status != RAW_INPUT_EATEN) - { - /* Point to payload. */ - pbuf_remove_header(p, hlen_tot); -#else /* LWIP_RAW */ - { -#endif /* LWIP_RAW */ - switch (*nexth) { - case IP6_NEXTH_NONE: - pbuf_free(p); - break; -#if LWIP_UDP - case IP6_NEXTH_UDP: -#if LWIP_UDPLITE - case IP6_NEXTH_UDPLITE: -#endif /* LWIP_UDPLITE */ - udp_input(p, inp); - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case IP6_NEXTH_TCP: - tcp_input(p, inp); - break; -#endif /* LWIP_TCP */ -#if LWIP_ICMP6 - case IP6_NEXTH_ICMP6: - icmp6_input(p, inp); - break; -#endif /* LWIP_ICMP */ - default: -#if LWIP_RAW - if (raw_status == RAW_INPUT_DELIVERED) { - /* @todo: ipv6 mib in-delivers? */ - } else -#endif /* LWIP_RAW */ - { -#if LWIP_ICMP6 - /* p points to IPv6 header again for raw_input. */ - pbuf_add_header_force(p, hlen_tot); - /* send ICMP parameter problem unless it was a multicast or ICMPv6 */ - if ((!ip6_addr_ismulticast(ip6_current_dest_addr())) && - (IP6H_NEXTH(ip6hdr) != IP6_NEXTH_ICMP6)) { - icmp6_param_problem(p, ICMP6_PP_HEADER, nexth); - } -#endif /* LWIP_ICMP */ - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: Unsupported transport protocol %"U16_F"\n", (u16_t)IP6H_NEXTH(ip6hdr))); - IP6_STATS_INC(ip6.proterr); - IP6_STATS_INC(ip6.drop); - } - pbuf_free(p); - break; - } - } - -ip6_input_cleanup: - ip_data.current_netif = NULL; - ip_data.current_input_netif = NULL; - ip_data.current_ip6_header = NULL; - ip_data.current_ip_header_tot_len = 0; - ip6_addr_set_zero(ip6_current_src_addr()); - ip6_addr_set_zero(ip6_current_dest_addr()); - - return ERR_OK; -} - - -/** - * Sends an IPv6 packet on a network interface. This function constructs - * the IPv6 header. If the source IPv6 address is NULL, the IPv6 "ANY" address is - * used as source (usually during network startup). If the source IPv6 address it - * IP6_ADDR_ANY, the most appropriate IPv6 address of the outgoing network - * interface is filled in as source address. If the destination IPv6 address is - * LWIP_IP_HDRINCL, p is assumed to already include an IPv6 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 == LWIP_IP_HDRINCL, p already includes an - IPv6 header and p->payload points to that IPv6 header) - * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an - * IP address of the netif is selected and used as source address. - * if src == NULL, IP6_ADDR_ANY is used as source) (src is possibly not - * properly zoned) - * @param dest the destination IPv6 address to send the packet to (possibly not - * properly zoned) - * @param hl the Hop Limit value to be set in the IPv6 header - * @param tc the Traffic Class value to be set in the IPv6 header - * @param nexth the Next Header to be set in the IPv6 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 IPv6/LINK headers - * returns errors returned by netif->output_ip6 - */ -err_t -ip6_output_if(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, - u8_t hl, u8_t tc, - u8_t nexth, struct netif *netif) -{ - const ip6_addr_t *src_used = src; - if (dest != LWIP_IP_HDRINCL) { - if (src != NULL && ip6_addr_isany(src)) { - src_used = ip_2_ip6(ip6_select_source_address(netif, dest)); - if ((src_used == NULL) || ip6_addr_isany(src_used)) { - /* No appropriate source address was found for this packet. */ - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n")); - IP6_STATS_INC(ip6.rterr); - return ERR_RTE; - } - } - } - return ip6_output_if_src(p, src_used, dest, hl, tc, nexth, netif); -} - -/** - * Same as ip6_output_if() but 'src' address is not replaced by netif address - * when it is 'any'. - */ -err_t -ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, - u8_t hl, u8_t tc, - u8_t nexth, struct netif *netif) -{ - struct ip6_hdr *ip6hdr; - ip6_addr_t dest_addr; - - LWIP_ASSERT_CORE_LOCKED(); - LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); - - /* Should the IPv6 header be generated or is it already included in p? */ - if (dest != LWIP_IP_HDRINCL) { -#if LWIP_IPV6_SCOPES - /* If the destination address is scoped but lacks a zone, add a zone now, - * based on the outgoing interface. The lower layers (e.g., nd6) absolutely - * require addresses to be properly zoned for correctness. In some cases, - * earlier attempts will have been made to add a zone to the destination, - * but this function is the only one that is called in all (other) cases, - * so we must do this here. */ - if (ip6_addr_lacks_zone(dest, IP6_UNKNOWN)) { - ip6_addr_copy(dest_addr, *dest); - ip6_addr_assign_zone(&dest_addr, IP6_UNKNOWN, netif); - dest = &dest_addr; - } -#endif /* LWIP_IPV6_SCOPES */ - - /* generate IPv6 header */ - if (pbuf_add_header(p, IP6_HLEN)) { - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n")); - IP6_STATS_INC(ip6.err); - return ERR_BUF; - } - - ip6hdr = (struct ip6_hdr *)p->payload; - LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr", - (p->len >= sizeof(struct ip6_hdr))); - - IP6H_HOPLIM_SET(ip6hdr, hl); - IP6H_NEXTH_SET(ip6hdr, nexth); - - /* dest cannot be NULL here */ - ip6_addr_copy_to_packed(ip6hdr->dest, *dest); - - IP6H_VTCFL_SET(ip6hdr, 6, tc, 0); - IP6H_PLEN_SET(ip6hdr, (u16_t)(p->tot_len - IP6_HLEN)); - - if (src == NULL) { - src = IP6_ADDR_ANY6; - } - /* src cannot be NULL here */ - ip6_addr_copy_to_packed(ip6hdr->src, *src); - - } else { - /* IP header already included in p */ - ip6hdr = (struct ip6_hdr *)p->payload; - ip6_addr_copy_from_packed(dest_addr, ip6hdr->dest); - ip6_addr_assign_zone(&dest_addr, IP6_UNKNOWN, netif); - dest = &dest_addr; - } - - IP6_STATS_INC(ip6.xmit); - - LWIP_DEBUGF(IP6_DEBUG, ("ip6_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], (u16_t)netif->num)); - ip6_debug_print(p); - -#if ENABLE_LOOPBACK - { - int i; -#if !LWIP_HAVE_LOOPIF - if (ip6_addr_isloopback(dest)) { - return netif_loop_output(netif, p); - } -#endif /* !LWIP_HAVE_LOOPIF */ - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_cmp(dest, netif_ip6_addr(netif, i))) { - /* Packet to self, enqueue it for loopback */ - LWIP_DEBUGF(IP6_DEBUG, ("netif_loop_output()\n")); - return netif_loop_output(netif, p); - } - } - } -#if LWIP_MULTICAST_TX_OPTIONS - if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { - netif_loop_output(netif, p); - } -#endif /* LWIP_MULTICAST_TX_OPTIONS */ -#endif /* ENABLE_LOOPBACK */ -#if LWIP_IPV6_FRAG - /* don't fragment if interface has mtu set to 0 [loopif] */ - if (netif_mtu6(netif) && (p->tot_len > nd6_get_destination_mtu(dest, netif))) { - return ip6_frag(p, netif, dest); - } -#endif /* LWIP_IPV6_FRAG */ - - LWIP_DEBUGF(IP6_DEBUG, ("netif->output_ip6()\n")); - return netif->output_ip6(netif, p, dest); -} - -/** - * Simple interface to ip6_output_if. It finds the outgoing network - * interface and calls upon ip6_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 == LWIP_IP_HDRINCL, p already includes an - IPv6 header and p->payload points to that IPv6 header) - * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an - * IP address of the netif is selected and used as source address. - * if src == NULL, IP6_ADDR_ANY is used as source) - * @param dest the destination IPv6 address to send the packet to - * @param hl the Hop Limit value to be set in the IPv6 header - * @param tc the Traffic Class value to be set in the IPv6 header - * @param nexth the Next Header to be set in the IPv6 header - * - * @return ERR_RTE if no route is found - * see ip_output_if() for more return values - */ -err_t -ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, - u8_t hl, u8_t tc, u8_t nexth) -{ - struct netif *netif; - struct ip6_hdr *ip6hdr; - ip6_addr_t src_addr, dest_addr; - - LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); - - if (dest != LWIP_IP_HDRINCL) { - netif = ip6_route(src, dest); - } else { - /* IP header included in p, read addresses. */ - ip6hdr = (struct ip6_hdr *)p->payload; - ip6_addr_copy_from_packed(src_addr, ip6hdr->src); - ip6_addr_copy_from_packed(dest_addr, ip6hdr->dest); - netif = ip6_route(&src_addr, &dest_addr); - } - - if (netif == NULL) { - LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", - IP6_ADDR_BLOCK1(dest), - IP6_ADDR_BLOCK2(dest), - IP6_ADDR_BLOCK3(dest), - IP6_ADDR_BLOCK4(dest), - IP6_ADDR_BLOCK5(dest), - IP6_ADDR_BLOCK6(dest), - IP6_ADDR_BLOCK7(dest), - IP6_ADDR_BLOCK8(dest))); - IP6_STATS_INC(ip6.rterr); - return ERR_RTE; - } - - return ip6_output_if(p, src, dest, hl, tc, nexth, netif); -} - - -#if LWIP_NETIF_USE_HINTS -/** Like ip6_output, but takes and addr_hint pointer that is passed on to netif->addr_hint - * before calling ip6_output_if. - * - * @param p the packet to send (p->payload points to the data, e.g. next - protocol header; if dest == LWIP_IP_HDRINCL, p already includes an - IPv6 header and p->payload points to that IPv6 header) - * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an - * IP address of the netif is selected and used as source address. - * if src == NULL, IP6_ADDR_ANY is used as source) - * @param dest the destination IPv6 address to send the packet to - * @param hl the Hop Limit value to be set in the IPv6 header - * @param tc the Traffic Class value to be set in the IPv6 header - * @param nexth the Next Header to be set in the IPv6 header - * @param netif_hint netif output hint pointer set to netif->hint before - * calling ip_output_if() - * - * @return ERR_RTE if no route is found - * see ip_output_if() for more return values - */ -err_t -ip6_output_hinted(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, - u8_t hl, u8_t tc, u8_t nexth, struct netif_hint *netif_hint) -{ - struct netif *netif; - struct ip6_hdr *ip6hdr; - ip6_addr_t src_addr, dest_addr; - err_t err; - - LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); - - if (dest != LWIP_IP_HDRINCL) { - netif = ip6_route(src, dest); - } else { - /* IP header included in p, read addresses. */ - ip6hdr = (struct ip6_hdr *)p->payload; - ip6_addr_copy_from_packed(src_addr, ip6hdr->src); - ip6_addr_copy_from_packed(dest_addr, ip6hdr->dest); - netif = ip6_route(&src_addr, &dest_addr); - } - - if (netif == NULL) { - LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", - IP6_ADDR_BLOCK1(dest), - IP6_ADDR_BLOCK2(dest), - IP6_ADDR_BLOCK3(dest), - IP6_ADDR_BLOCK4(dest), - IP6_ADDR_BLOCK5(dest), - IP6_ADDR_BLOCK6(dest), - IP6_ADDR_BLOCK7(dest), - IP6_ADDR_BLOCK8(dest))); - IP6_STATS_INC(ip6.rterr); - return ERR_RTE; - } - - NETIF_SET_HINTS(netif, netif_hint); - err = ip6_output_if(p, src, dest, hl, tc, nexth, netif); - NETIF_RESET_HINTS(netif); - - return err; -} -#endif /* LWIP_NETIF_USE_HINTS*/ - -#if LWIP_IPV6_MLD -/** - * Add a hop-by-hop options header with a router alert option and padding. - * - * Used by MLD when sending a Multicast listener report/done message. - * - * @param p the packet to which we will prepend the options header - * @param nexth the next header protocol number (e.g. IP6_NEXTH_ICMP6) - * @param value the value of the router alert option data (e.g. IP6_ROUTER_ALERT_VALUE_MLD) - * @return ERR_OK if hop-by-hop header was added, ERR_* otherwise - */ -err_t -ip6_options_add_hbh_ra(struct pbuf *p, u8_t nexth, u8_t value) -{ - u8_t *opt_data; - u32_t offset = 0; - struct ip6_hbh_hdr *hbh_hdr; - struct ip6_opt_hdr *opt_hdr; - - /* fixed 4 bytes for router alert option and 2 bytes padding */ - const u8_t hlen = (sizeof(struct ip6_opt_hdr) * 2) + IP6_ROUTER_ALERT_DLEN; - /* Move pointer to make room for hop-by-hop options header. */ - if (pbuf_add_header(p, sizeof(struct ip6_hbh_hdr) + hlen)) { - LWIP_DEBUGF(IP6_DEBUG, ("ip6_options: no space for options header\n")); - IP6_STATS_INC(ip6.err); - return ERR_BUF; - } - - /* Set fields of Hop-by-Hop header */ - hbh_hdr = (struct ip6_hbh_hdr *)p->payload; - IP6_HBH_NEXTH(hbh_hdr) = nexth; - hbh_hdr->_hlen = 0; - offset = IP6_HBH_HLEN; - - /* Set router alert options to Hop-by-Hop extended option header */ - opt_hdr = (struct ip6_opt_hdr *)((u8_t *)hbh_hdr + offset); - IP6_OPT_TYPE(opt_hdr) = IP6_ROUTER_ALERT_OPTION; - IP6_OPT_DLEN(opt_hdr) = IP6_ROUTER_ALERT_DLEN; - offset += IP6_OPT_HLEN; - - /* Set router alert option data */ - opt_data = (u8_t *)hbh_hdr + offset; - opt_data[0] = value; - opt_data[1] = 0; - offset += IP6_OPT_DLEN(opt_hdr); - - /* add 2 bytes padding to make 8 bytes Hop-by-Hop header length */ - opt_hdr = (struct ip6_opt_hdr *)((u8_t *)hbh_hdr + offset); - IP6_OPT_TYPE(opt_hdr) = IP6_PADN_OPTION; - IP6_OPT_DLEN(opt_hdr) = 0; - - return ERR_OK; -} -#endif /* LWIP_IPV6_MLD */ - -#if IP6_DEBUG -/* Print an IPv6 header by using LWIP_DEBUGF - * @param p an IPv6 packet, p->payload pointing to the IPv6 header - */ -void -ip6_debug_print(struct pbuf *p) -{ - struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; - - LWIP_DEBUGF(IP6_DEBUG, ("IPv6 header:\n")); - LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP6_DEBUG, ("| %2"U16_F" | %3"U16_F" | %7"U32_F" | (ver, class, flow)\n", - IP6H_V(ip6hdr), - IP6H_TC(ip6hdr), - IP6H_FL(ip6hdr))); - LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP6_DEBUG, ("| %5"U16_F" | %3"U16_F" | %3"U16_F" | (plen, nexth, hopl)\n", - IP6H_PLEN(ip6hdr), - IP6H_NEXTH(ip6hdr), - IP6H_HOPLIM(ip6hdr))); - LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (src)\n", - IP6_ADDR_BLOCK1(&(ip6hdr->src)), - IP6_ADDR_BLOCK2(&(ip6hdr->src)), - IP6_ADDR_BLOCK3(&(ip6hdr->src)), - IP6_ADDR_BLOCK4(&(ip6hdr->src)))); - LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n", - IP6_ADDR_BLOCK5(&(ip6hdr->src)), - IP6_ADDR_BLOCK6(&(ip6hdr->src)), - IP6_ADDR_BLOCK7(&(ip6hdr->src)), - IP6_ADDR_BLOCK8(&(ip6hdr->src)))); - LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (dest)\n", - IP6_ADDR_BLOCK1(&(ip6hdr->dest)), - IP6_ADDR_BLOCK2(&(ip6hdr->dest)), - IP6_ADDR_BLOCK3(&(ip6hdr->dest)), - IP6_ADDR_BLOCK4(&(ip6hdr->dest)))); - LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n", - IP6_ADDR_BLOCK5(&(ip6hdr->dest)), - IP6_ADDR_BLOCK6(&(ip6hdr->dest)), - IP6_ADDR_BLOCK7(&(ip6hdr->dest)), - IP6_ADDR_BLOCK8(&(ip6hdr->dest)))); - LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); -} -#endif /* IP6_DEBUG */ - -#endif /* LWIP_IPV6 */ diff --git a/core/c/core/ipv6/ip6_addr.c b/core/c/core/ipv6/ip6_addr.c deleted file mode 100755 index aafba72..0000000 --- a/core/c/core/ipv6/ip6_addr.c +++ /dev/null @@ -1,343 +0,0 @@ -/** - * @file - * - * IPv6 addresses. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * Functions for handling IPv6 addresses. - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#include "lwip/opt.h" - -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/ip_addr.h" -#include "lwip/def.h" - -#include - -#if LWIP_IPV4 -#include "lwip/ip4_addr.h" /* for ip6addr_aton to handle IPv4-mapped addresses */ -#endif /* LWIP_IPV4 */ - -/* used by IP6_ADDR_ANY(6) in ip6_addr.h */ -const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul); - -#define lwip_xchar(i) ((char)((i) < 10 ? '0' + (i) : 'A' + (i) - 10)) - -/** - * Check whether "cp" is a valid ascii representation - * of an IPv6 address and convert to a binary address. - * Returns 1 if the address is valid, 0 if not. - * - * @param cp IPv6 address in ascii representation (e.g. "FF01::1") - * @param addr pointer to which to save the ip address in network order - * @return 1 if cp could be converted to addr, 0 on failure - */ -int -ip6addr_aton(const char *cp, ip6_addr_t *addr) -{ - u32_t addr_index, zero_blocks, current_block_index, current_block_value; - const char *s; -#if LWIP_IPV4 - int check_ipv4_mapped = 0; -#endif /* LWIP_IPV4 */ - - /* Count the number of colons, to count the number of blocks in a "::" sequence - zero_blocks may be 1 even if there are no :: sequences */ - zero_blocks = 8; - for (s = cp; *s != 0; s++) { - if (*s == ':') { - zero_blocks--; -#if LWIP_IPV4 - } else if (*s == '.') { - if ((zero_blocks == 5) ||(zero_blocks == 2)) { - check_ipv4_mapped = 1; - /* last block could be the start of an IPv4 address */ - zero_blocks--; - } else { - /* invalid format */ - return 0; - } - break; -#endif /* LWIP_IPV4 */ - } else if (!lwip_isxdigit(*s)) { - break; - } - } - - /* parse each block */ - addr_index = 0; - current_block_index = 0; - current_block_value = 0; - for (s = cp; *s != 0; s++) { - if (*s == ':') { - if (addr) { - if (current_block_index & 0x1) { - addr->addr[addr_index++] |= current_block_value; - } - else { - addr->addr[addr_index] = current_block_value << 16; - } - } - current_block_index++; -#if LWIP_IPV4 - if (check_ipv4_mapped) { - if (current_block_index == 6) { - ip4_addr_t ip4; - int ret = ip4addr_aton(s + 1, &ip4); - if (ret) { - if (addr) { - addr->addr[3] = lwip_htonl(ip4.addr); - current_block_index++; - goto fix_byte_order_and_return; - } - return 1; - } - } - } -#endif /* LWIP_IPV4 */ - current_block_value = 0; - if (current_block_index > 7) { - /* address too long! */ - return 0; - } - if (s[1] == ':') { - if (s[2] == ':') { - /* invalid format: three successive colons */ - return 0; - } - s++; - /* "::" found, set zeros */ - while (zero_blocks > 0) { - zero_blocks--; - if (current_block_index & 0x1) { - addr_index++; - } else { - if (addr) { - addr->addr[addr_index] = 0; - } - } - current_block_index++; - if (current_block_index > 7) { - /* address too long! */ - return 0; - } - } - } - } else if (lwip_isxdigit(*s)) { - /* add current digit */ - current_block_value = (current_block_value << 4) + - (lwip_isdigit(*s) ? (u32_t)(*s - '0') : - (u32_t)(10 + (lwip_islower(*s) ? *s - 'a' : *s - 'A'))); - } else { - /* unexpected digit, space? CRLF? */ - break; - } - } - - if (addr) { - if (current_block_index & 0x1) { - addr->addr[addr_index++] |= current_block_value; - } - else { - addr->addr[addr_index] = current_block_value << 16; - } -#if LWIP_IPV4 -fix_byte_order_and_return: -#endif - /* convert to network byte order. */ - for (addr_index = 0; addr_index < 4; addr_index++) { - addr->addr[addr_index] = lwip_htonl(addr->addr[addr_index]); - } - - ip6_addr_clear_zone(addr); - } - - if (current_block_index != 7) { - return 0; - } - - return 1; -} - -/** - * Convert numeric IPv6 address into ASCII representation. - * returns ptr to static buffer; not reentrant! - * - * @param addr ip6 address in network order to convert - * @return pointer to a global static (!) buffer that holds the ASCII - * representation of addr - */ -char * -ip6addr_ntoa(const ip6_addr_t *addr) -{ - static char str[40]; - return ip6addr_ntoa_r(addr, str, 40); -} - -/** - * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. - * - * @param addr ip6 address in network order to convert - * @param buf target buffer where the string is stored - * @param buflen length of buf - * @return either pointer to buf which now holds the ASCII - * representation of addr or NULL if buf was too small - */ -char * -ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen) -{ - u32_t current_block_index, current_block_value, next_block_value; - s32_t i; - u8_t zero_flag, empty_block_flag; - -#if LWIP_IPV4 - if (ip6_addr_isipv4mappedipv6(addr)) { - /* This is an IPv4 mapped address */ - ip4_addr_t addr4; - char *ret; -#define IP4MAPPED_HEADER "::FFFF:" - char *buf_ip4 = buf + sizeof(IP4MAPPED_HEADER) - 1; - int buflen_ip4 = buflen - sizeof(IP4MAPPED_HEADER) + 1; - if (buflen < (int)sizeof(IP4MAPPED_HEADER)) { - return NULL; - } - memcpy(buf, IP4MAPPED_HEADER, sizeof(IP4MAPPED_HEADER)); - addr4.addr = addr->addr[3]; - ret = ip4addr_ntoa_r(&addr4, buf_ip4, buflen_ip4); - if (ret != buf_ip4) { - return NULL; - } - return buf; - } -#endif /* LWIP_IPV4 */ - i = 0; - empty_block_flag = 0; /* used to indicate a zero chain for "::' */ - - for (current_block_index = 0; current_block_index < 8; current_block_index++) { - /* get the current 16-bit block */ - current_block_value = lwip_htonl(addr->addr[current_block_index >> 1]); - if ((current_block_index & 0x1) == 0) { - current_block_value = current_block_value >> 16; - } - current_block_value &= 0xffff; - - /* Check for empty block. */ - if (current_block_value == 0) { - if (current_block_index == 7 && empty_block_flag == 1) { - /* special case, we must render a ':' for the last block. */ - buf[i++] = ':'; - if (i >= buflen) { - return NULL; - } - break; - } - if (empty_block_flag == 0) { - /* generate empty block "::", but only if more than one contiguous zero block, - * according to current formatting suggestions RFC 5952. */ - next_block_value = lwip_htonl(addr->addr[(current_block_index + 1) >> 1]); - if ((current_block_index & 0x1) == 0x01) { - next_block_value = next_block_value >> 16; - } - next_block_value &= 0xffff; - if (next_block_value == 0) { - empty_block_flag = 1; - buf[i++] = ':'; - if (i >= buflen) { - return NULL; - } - continue; /* move on to next block. */ - } - } else if (empty_block_flag == 1) { - /* move on to next block. */ - continue; - } - } else if (empty_block_flag == 1) { - /* Set this flag value so we don't produce multiple empty blocks. */ - empty_block_flag = 2; - } - - if (current_block_index > 0) { - buf[i++] = ':'; - if (i >= buflen) { - return NULL; - } - } - - if ((current_block_value & 0xf000) == 0) { - zero_flag = 1; - } else { - buf[i++] = lwip_xchar(((current_block_value & 0xf000) >> 12)); - zero_flag = 0; - if (i >= buflen) { - return NULL; - } - } - - if (((current_block_value & 0xf00) == 0) && (zero_flag)) { - /* do nothing */ - } else { - buf[i++] = lwip_xchar(((current_block_value & 0xf00) >> 8)); - zero_flag = 0; - if (i >= buflen) { - return NULL; - } - } - - if (((current_block_value & 0xf0) == 0) && (zero_flag)) { - /* do nothing */ - } - else { - buf[i++] = lwip_xchar(((current_block_value & 0xf0) >> 4)); - zero_flag = 0; - if (i >= buflen) { - return NULL; - } - } - - buf[i++] = lwip_xchar((current_block_value & 0xf)); - if (i >= buflen) { - return NULL; - } - } - - buf[i] = 0; - - return buf; -} - -#endif /* LWIP_IPV6 */ diff --git a/core/c/core/ipv6/ip6_frag.c b/core/c/core/ipv6/ip6_frag.c deleted file mode 100755 index 0f277b6..0000000 --- a/core/c/core/ipv6/ip6_frag.c +++ /dev/null @@ -1,862 +0,0 @@ -/** - * @file - * - * IPv6 fragmentation and reassembly. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#include "lwip/opt.h" -#include "lwip/ip6_frag.h" -#include "lwip/ip6.h" -#include "lwip/icmp6.h" -#include "lwip/nd6.h" -#include "lwip/ip.h" - -#include "lwip/pbuf.h" -#include "lwip/memp.h" -#include "lwip/stats.h" - -#include - -#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ - - -/** Setting this to 0, you can turn off checking the fragments for overlapping - * regions. The code gets a little smaller. Only use this if you know that - * overlapping won't occur on your network! */ -#ifndef IP_REASS_CHECK_OVERLAP -#define IP_REASS_CHECK_OVERLAP 1 -#endif /* IP_REASS_CHECK_OVERLAP */ - -/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is - * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller. - * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA - * is set to 1, so one datagram can be reassembled at a time, only. */ -#ifndef IP_REASS_FREE_OLDEST -#define IP_REASS_FREE_OLDEST 1 -#endif /* IP_REASS_FREE_OLDEST */ - -#if IPV6_FRAG_COPYHEADER -/* The number of bytes we need to "borrow" from (i.e., overwrite in) the header - * that precedes the fragment header for reassembly pruposes. */ -#define IPV6_FRAG_REQROOM ((s16_t)(sizeof(struct ip6_reass_helper) - IP6_FRAG_HLEN)) -#endif - -#define IP_REASS_FLAG_LASTFRAG 0x01 - -/** This is a helper struct which holds the starting - * offset and the ending offset of this fragment to - * easily chain the fragments. - * It has the same packing requirements as the IPv6 header, since it replaces - * the Fragment Header in memory in incoming fragments to keep - * track of the various fragments. - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip6_reass_helper { - PACK_STRUCT_FIELD(struct pbuf *next_pbuf); - PACK_STRUCT_FIELD(u16_t start); - PACK_STRUCT_FIELD(u16_t end); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/* static variables */ -static struct ip6_reassdata *reassdatagrams; -static u16_t ip6_reass_pbufcount; - -/* Forward declarations. */ -static void ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr); -#if IP_REASS_FREE_OLDEST -static void ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed); -#endif /* IP_REASS_FREE_OLDEST */ - -void -ip6_reass_tmr(void) -{ - struct ip6_reassdata *r, *tmp; - -#if !IPV6_FRAG_COPYHEADER - LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1", - sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN); -#endif /* !IPV6_FRAG_COPYHEADER */ - - r = reassdatagrams; - while (r != NULL) { - /* Decrement the timer. Once it reaches 0, - * clean up the incomplete fragment assembly */ - if (r->timer > 0) { - r->timer--; - r = r->next; - } else { - /* reassembly timed out */ - tmp = r; - /* get the next pointer before freeing */ - r = r->next; - /* free the helper struct and all enqueued pbufs */ - ip6_reass_free_complete_datagram(tmp); - } - } -} - -/** - * Free a datagram (struct ip6_reassdata) and all its pbufs. - * Updates the total count of enqueued pbufs (ip6_reass_pbufcount), - * sends an ICMP time exceeded packet. - * - * @param ipr datagram to free - */ -static void -ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr) -{ - struct ip6_reassdata *prev; - u16_t pbufs_freed = 0; - u16_t clen; - struct pbuf *p; - struct ip6_reass_helper *iprh; - -#if LWIP_ICMP6 - iprh = (struct ip6_reass_helper *)ipr->p->payload; - if (iprh->start == 0) { - /* The first fragment was received, send ICMP time exceeded. */ - /* First, de-queue the first pbuf from r->p. */ - p = ipr->p; - ipr->p = iprh->next_pbuf; - /* Restore the part that we've overwritten with our helper structure, or we - * might send garbage (and disclose a pointer) in the ICMPv6 reply. */ - MEMCPY(p->payload, ipr->orig_hdr, sizeof(iprh)); - /* Then, move back to the original ipv6 header (we are now pointing to Fragment header). - This cannot fail since we already checked when receiving this fragment. */ - if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)ipr->iphdr))) { - LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0); - } - else { - /* Reconstruct the zoned source and destination addresses, so that we do - * not end up sending the ICMP response over the wrong link. */ - ip6_addr_t src_addr, dest_addr; - ip6_addr_copy_from_packed(src_addr, IPV6_FRAG_SRC(ipr)); - ip6_addr_set_zone(&src_addr, ipr->src_zone); - ip6_addr_copy_from_packed(dest_addr, IPV6_FRAG_DEST(ipr)); - ip6_addr_set_zone(&dest_addr, ipr->dest_zone); - /* Send the actual ICMP response. */ - icmp6_time_exceeded_with_addrs(p, ICMP6_TE_FRAG, &src_addr, &dest_addr); - } - clen = pbuf_clen(p); - LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); - pbufs_freed = (u16_t)(pbufs_freed + clen); - pbuf_free(p); - } -#endif /* LWIP_ICMP6 */ - - /* First, free all received pbufs. The individual pbufs need to be released - separately as they have not yet been chained */ - p = ipr->p; - while (p != NULL) { - struct pbuf *pcur; - iprh = (struct ip6_reass_helper *)p->payload; - pcur = p; - /* get the next pointer before freeing */ - p = iprh->next_pbuf; - clen = pbuf_clen(pcur); - LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); - pbufs_freed = (u16_t)(pbufs_freed + clen); - pbuf_free(pcur); - } - - /* Then, unchain the struct ip6_reassdata from the list and free it. */ - if (ipr == reassdatagrams) { - reassdatagrams = ipr->next; - } else { - prev = reassdatagrams; - while (prev != NULL) { - if (prev->next == ipr) { - break; - } - prev = prev->next; - } - if (prev != NULL) { - prev->next = ipr->next; - } - } - memp_free(MEMP_IP6_REASSDATA, ipr); - - /* Finally, update number of pbufs in reassembly queue */ - LWIP_ASSERT("ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed); - ip6_reass_pbufcount = (u16_t)(ip6_reass_pbufcount - pbufs_freed); -} - -#if IP_REASS_FREE_OLDEST -/** - * Free the oldest datagram to make room for enqueueing new fragments. - * The datagram ipr is not freed! - * - * @param ipr ip6_reassdata for the current fragment - * @param pbufs_needed number of pbufs needed to enqueue - * (used for freeing other datagrams if not enough space) - */ -static void -ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed) -{ - struct ip6_reassdata *r, *oldest; - - /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, - * but don't free the current datagram! */ - do { - r = oldest = reassdatagrams; - while (r != NULL) { - if (r != ipr) { - if (r->timer <= oldest->timer) { - /* older than the previous oldest */ - oldest = r; - } - } - r = r->next; - } - if (oldest == ipr) { - /* nothing to free, ipr is the only element on the list */ - return; - } - if (oldest != NULL) { - ip6_reass_free_complete_datagram(oldest); - } - } while (((ip6_reass_pbufcount + pbufs_needed) > IP_REASS_MAX_PBUFS) && (reassdatagrams != NULL)); -} -#endif /* IP_REASS_FREE_OLDEST */ - -/** - * Reassembles incoming IPv6 fragments into an IPv6 datagram. - * - * @param p points to the IPv6 Fragment Header - * @return NULL if reassembly is incomplete, pbuf pointing to - * IPv6 Header if reassembly is complete - */ -struct pbuf * -ip6_reass(struct pbuf *p) -{ - struct ip6_reassdata *ipr, *ipr_prev; - struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; - struct ip6_frag_hdr *frag_hdr; - u16_t offset, len, start, end; - ptrdiff_t hdrdiff; - u16_t clen; - u8_t valid = 1; - struct pbuf *q, *next_pbuf; - - IP6_FRAG_STATS_INC(ip6_frag.recv); - - /* ip6_frag_hdr must be in the first pbuf, not chained. Checked by caller. */ - LWIP_ASSERT("IPv6 fragment header does not fit in first pbuf", - p->len >= sizeof(struct ip6_frag_hdr)); - - frag_hdr = (struct ip6_frag_hdr *) p->payload; - - clen = pbuf_clen(p); - - offset = lwip_ntohs(frag_hdr->_fragment_offset); - - /* Calculate fragment length from IPv6 payload length. - * Adjust for headers before Fragment Header. - * And finally adjust by Fragment Header length. */ - len = lwip_ntohs(ip6_current_header()->_plen); - hdrdiff = (u8_t*)p->payload - (const u8_t*)ip6_current_header(); - LWIP_ASSERT("not a valid pbuf (ip6_input check missing?)", hdrdiff <= 0xFFFF); - LWIP_ASSERT("not a valid pbuf (ip6_input check missing?)", hdrdiff >= IP6_HLEN); - hdrdiff -= IP6_HLEN; - hdrdiff += IP6_FRAG_HLEN; - if (hdrdiff > len) { - IP6_FRAG_STATS_INC(ip6_frag.proterr); - goto nullreturn; - } - len = (u16_t)(len - hdrdiff); - start = (offset & IP6_FRAG_OFFSET_MASK); - if (start > (0xFFFF - len)) { - /* u16_t overflow, cannot handle this */ - IP6_FRAG_STATS_INC(ip6_frag.proterr); - 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_prev = NULL; ipr != NULL; ipr = ipr->next) { - /* Check if the incoming fragment matches the one currently present - in the reassembly buffer. If so, we proceed with copying the - fragment into the buffer. */ - if ((frag_hdr->_identification == ipr->identification) && - ip6_addr_cmp_packed(ip6_current_src_addr(), &(IPV6_FRAG_SRC(ipr)), ipr->src_zone) && - ip6_addr_cmp_packed(ip6_current_dest_addr(), &(IPV6_FRAG_DEST(ipr)), ipr->dest_zone)) { - IP6_FRAG_STATS_INC(ip6_frag.cachehit); - break; - } - ipr_prev = ipr; - } - - if (ipr == NULL) { - /* Enqueue a new datagram into the datagram queue */ - ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); - if (ipr == NULL) { -#if IP_REASS_FREE_OLDEST - /* Make room and try again. */ - ip6_reass_remove_oldest_datagram(ipr, clen); - ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); - if (ipr != NULL) { - /* re-search ipr_prev since it might have been removed */ - for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { - if (ipr_prev->next == ipr) { - break; - } - } - } else -#endif /* IP_REASS_FREE_OLDEST */ - { - IP6_FRAG_STATS_INC(ip6_frag.memerr); - goto nullreturn; - } - } - - memset(ipr, 0, sizeof(struct ip6_reassdata)); - ipr->timer = IPV6_REASS_MAXAGE; - - /* enqueue the new structure to the front of the list */ - ipr->next = reassdatagrams; - reassdatagrams = ipr; - - /* Use the current IPv6 header for src/dest address reference. - * Eventually, we will replace it when we get the first fragment - * (it might be this one, in any case, it is done later). */ - /* need to use the none-const pointer here: */ - ipr->iphdr = ip_data.current_ip6_header; -#if IPV6_FRAG_COPYHEADER - MEMCPY(&ipr->src, &ip6_current_header()->src, sizeof(ipr->src)); - MEMCPY(&ipr->dest, &ip6_current_header()->dest, sizeof(ipr->dest)); -#endif /* IPV6_FRAG_COPYHEADER */ -#if LWIP_IPV6_SCOPES - /* Also store the address zone information. - * @todo It is possible that due to netif destruction and recreation, the - * stored zones end up resolving to a different interface. In that case, we - * risk sending a "time exceeded" ICMP response over the wrong link. - * Ideally, netif destruction would clean up matching pending reassembly - * structures, but custom zone mappings would make that non-trivial. */ - ipr->src_zone = ip6_addr_zone(ip6_current_src_addr()); - ipr->dest_zone = ip6_addr_zone(ip6_current_dest_addr()); -#endif /* LWIP_IPV6_SCOPES */ - /* copy the fragmented packet id. */ - ipr->identification = frag_hdr->_identification; - - /* copy the nexth field */ - ipr->nexth = frag_hdr->_nexth; - } - - /* Check if we are allowed to enqueue more datagrams. */ - if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { -#if IP_REASS_FREE_OLDEST - ip6_reass_remove_oldest_datagram(ipr, clen); - if ((ip6_reass_pbufcount + clen) <= IP_REASS_MAX_PBUFS) { - /* re-search ipr_prev since it might have been removed */ - for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { - if (ipr_prev->next == ipr) { - break; - } - } - } else -#endif /* IP_REASS_FREE_OLDEST */ - { - /* @todo: send ICMPv6 time exceeded here? */ - /* drop this pbuf */ - IP6_FRAG_STATS_INC(ip6_frag.memerr); - goto nullreturn; - } - } - - /* Overwrite Fragment Header with our own helper struct. */ -#if IPV6_FRAG_COPYHEADER - if (IPV6_FRAG_REQROOM > 0) { - /* Make room for struct ip6_reass_helper (only required if sizeof(void*) > 4). - This cannot fail since we already checked when receiving this fragment. */ - u8_t hdrerr = pbuf_header_force(p, IPV6_FRAG_REQROOM); - LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */ - LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0); - } -#else /* IPV6_FRAG_COPYHEADER */ - LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1", - sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN); -#endif /* IPV6_FRAG_COPYHEADER */ - - /* Prepare the pointer to the helper structure, and its initial values. - * Do not yet write to the structure itself, as we still have to make a - * backup of the original data, and we should not do that until we know for - * sure that we are going to add this packet to the list. */ - iprh = (struct ip6_reass_helper *)p->payload; - next_pbuf = NULL; - end = (u16_t)(start + len); - - /* find the right place to insert this pbuf */ - /* Iterate through until we either get to the end of the list (append), - * or we find on with a larger offset (insert). */ - for (q = ipr->p; q != NULL;) { - iprh_tmp = (struct ip6_reass_helper*)q->payload; - if (start < iprh_tmp->start) { -#if IP_REASS_CHECK_OVERLAP - if (end > iprh_tmp->start) { - /* fragment overlaps with following, throw away */ - IP6_FRAG_STATS_INC(ip6_frag.proterr); - goto nullreturn; - } - if (iprh_prev != NULL) { - if (start < iprh_prev->end) { - /* fragment overlaps with previous, throw away */ - IP6_FRAG_STATS_INC(ip6_frag.proterr); - goto nullreturn; - } - } -#endif /* IP_REASS_CHECK_OVERLAP */ - /* the new pbuf should be inserted before this */ - next_pbuf = q; - if (iprh_prev != NULL) { - /* not the fragment with the lowest offset */ - iprh_prev->next_pbuf = p; - } else { - /* fragment with the lowest offset */ - ipr->p = p; - } - break; - } else if (start == iprh_tmp->start) { - /* received the same datagram twice: no need to keep the datagram */ - goto nullreturn; -#if IP_REASS_CHECK_OVERLAP - } else if (start < iprh_tmp->end) { - /* overlap: no need to keep the new datagram */ - IP6_FRAG_STATS_INC(ip6_frag.proterr); - goto nullreturn; -#endif /* IP_REASS_CHECK_OVERLAP */ - } else { - /* Check if the fragments received so far have no gaps. */ - if (iprh_prev != NULL) { - if (iprh_prev->end != iprh_tmp->start) { - /* There is a fragment missing between the current - * and the previous fragment */ - valid = 0; - } - } - } - q = iprh_tmp->next_pbuf; - iprh_prev = iprh_tmp; - } - - /* If q is NULL, then we made it to the end of the list. Determine what to do now */ - if (q == NULL) { - if (iprh_prev != NULL) { - /* this is (for now), the fragment with the highest offset: - * chain it to the last fragment */ -#if IP_REASS_CHECK_OVERLAP - LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= start); -#endif /* IP_REASS_CHECK_OVERLAP */ - iprh_prev->next_pbuf = p; - if (iprh_prev->end != start) { - valid = 0; - } - } else { -#if IP_REASS_CHECK_OVERLAP - LWIP_ASSERT("no previous fragment, this must be the first fragment!", - ipr->p == NULL); -#endif /* IP_REASS_CHECK_OVERLAP */ - /* this is the first fragment we ever received for this ip datagram */ - ipr->p = p; - } - } - - /* Track the current number of pbufs current 'in-flight', in order to limit - the number of fragments that may be enqueued at any one time */ - ip6_reass_pbufcount = (u16_t)(ip6_reass_pbufcount + clen); - - /* Remember IPv6 header if this is the first fragment. */ - if (start == 0) { - /* need to use the none-const pointer here: */ - ipr->iphdr = ip_data.current_ip6_header; - /* Make a backup of the part of the packet data that we are about to - * overwrite, so that we can restore the original later. */ - MEMCPY(ipr->orig_hdr, p->payload, sizeof(*iprh)); - /* For IPV6_FRAG_COPYHEADER there is no need to copy src/dst again, as they - * will be the same as they were. With LWIP_IPV6_SCOPES, the same applies - * to the source/destination zones. */ - } - /* Only after the backup do we get to fill in the actual helper structure. */ - iprh->next_pbuf = next_pbuf; - iprh->start = start; - iprh->end = end; - - /* If this is the last fragment, calculate total packet length. */ - if ((offset & IP6_FRAG_MORE_FLAG) == 0) { - ipr->datagram_len = iprh->end; - } - - /* Additional validity tests: we have received first and last fragment. */ - iprh_tmp = (struct ip6_reass_helper*)ipr->p->payload; - if (iprh_tmp->start != 0) { - valid = 0; - } - if (ipr->datagram_len == 0) { - valid = 0; - } - - /* Final validity test: no gaps between current and last fragment. */ - iprh_prev = iprh; - q = iprh->next_pbuf; - while ((q != NULL) && valid) { - iprh = (struct ip6_reass_helper*)q->payload; - if (iprh_prev->end != iprh->start) { - valid = 0; - break; - } - iprh_prev = iprh; - q = iprh->next_pbuf; - } - - if (valid) { - /* All fragments have been received */ - struct ip6_hdr* iphdr_ptr; - - /* chain together the pbufs contained within the ip6_reassdata list. */ - iprh = (struct ip6_reass_helper*) ipr->p->payload; - while (iprh != NULL) { - next_pbuf = iprh->next_pbuf; - if (next_pbuf != NULL) { - /* Save next helper struct (will be hidden in next step). */ - iprh_tmp = (struct ip6_reass_helper*)next_pbuf->payload; - - /* hide the fragment header for every succeeding fragment */ - pbuf_remove_header(next_pbuf, IP6_FRAG_HLEN); -#if IPV6_FRAG_COPYHEADER - if (IPV6_FRAG_REQROOM > 0) { - /* hide the extra bytes borrowed from ip6_hdr for struct ip6_reass_helper */ - u8_t hdrerr = pbuf_remove_header(next_pbuf, IPV6_FRAG_REQROOM); - LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */ - LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0); - } -#endif - pbuf_cat(ipr->p, next_pbuf); - } - else { - iprh_tmp = NULL; - } - - iprh = iprh_tmp; - } - - /* Get the first pbuf. */ - p = ipr->p; - -#if IPV6_FRAG_COPYHEADER - if (IPV6_FRAG_REQROOM > 0) { - u8_t hdrerr; - /* Restore (only) the bytes that we overwrote beyond the fragment header. - * Those bytes may belong to either the IPv6 header or an extension - * header placed before the fragment header. */ - MEMCPY(p->payload, ipr->orig_hdr, IPV6_FRAG_REQROOM); - /* get back room for struct ip6_reass_helper (only required if sizeof(void*) > 4) */ - hdrerr = pbuf_remove_header(p, IPV6_FRAG_REQROOM); - LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */ - LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0); - } -#endif - - /* We need to get rid of the fragment header itself, which is somewhere in - * the middle of the packet (but still in the first pbuf of the chain). - * Getting rid of the header is required by RFC 2460 Sec. 4.5 and necessary - * in order to be able to reassemble packets that are close to full size - * (i.e., around 65535 bytes). We simply move up all the headers before the - * fragment header, including the IPv6 header, and adjust the payload start - * accordingly. This works because all these headers are in the first pbuf - * of the chain, and because the caller adjusts all its pointers on - * successful reassembly. */ - MEMMOVE((u8_t*)ipr->iphdr + sizeof(struct ip6_frag_hdr), ipr->iphdr, - (size_t)((u8_t*)p->payload - (u8_t*)ipr->iphdr)); - - /* This is where the IPv6 header is now. */ - iphdr_ptr = (struct ip6_hdr*)((u8_t*)ipr->iphdr + - sizeof(struct ip6_frag_hdr)); - - /* Adjust datagram length by adding header lengths. */ - ipr->datagram_len = (u16_t)(ipr->datagram_len + ((u8_t*)p->payload - (u8_t*)iphdr_ptr) - - IP6_HLEN); - - /* Set payload length in ip header. */ - iphdr_ptr->_plen = lwip_htons(ipr->datagram_len); - - /* With the fragment header gone, we now need to adjust the next-header - * field of whatever header was originally before it. Since the packet made - * it through the original header processing routines at least up to the - * fragment header, we do not need any further sanity checks here. */ - if (IP6H_NEXTH(iphdr_ptr) == IP6_NEXTH_FRAGMENT) { - iphdr_ptr->_nexth = ipr->nexth; - } else { - u8_t *ptr = (u8_t *)iphdr_ptr + IP6_HLEN; - while (*ptr != IP6_NEXTH_FRAGMENT) { - ptr += 8 * (1 + ptr[1]); - } - *ptr = ipr->nexth; - } - - /* release the resources allocated for the fragment queue entry */ - if (reassdatagrams == ipr) { - /* it was the first in the list */ - reassdatagrams = ipr->next; - } else { - /* it wasn't the first, so it must have a valid 'prev' */ - LWIP_ASSERT("sanity check linked list", ipr_prev != NULL); - ipr_prev->next = ipr->next; - } - memp_free(MEMP_IP6_REASSDATA, ipr); - - /* adjust the number of pbufs currently queued for reassembly. */ - clen = pbuf_clen(p); - LWIP_ASSERT("ip6_reass_pbufcount >= clen", ip6_reass_pbufcount >= clen); - ip6_reass_pbufcount = (u16_t)(ip6_reass_pbufcount - clen); - - /* Move pbuf back to IPv6 header. This should never fail. */ - if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)iphdr_ptr))) { - LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0); - pbuf_free(p); - return NULL; - } - - /* Return the pbuf chain */ - return p; - } - /* the datagram is not (yet?) reassembled completely */ - return NULL; - -nullreturn: - IP6_FRAG_STATS_INC(ip6_frag.drop); - pbuf_free(p); - return NULL; -} - -#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ - -#if LWIP_IPV6 && LWIP_IPV6_FRAG - -#if !LWIP_NETIF_TX_SINGLE_PBUF -/** Allocate a new struct pbuf_custom_ref */ -static struct pbuf_custom_ref* -ip6_frag_alloc_pbuf_custom_ref(void) -{ - return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); -} - -/** Free a struct pbuf_custom_ref */ -static void -ip6_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) -{ - LWIP_ASSERT("p != NULL", p != NULL); - memp_free(MEMP_FRAG_PBUF, p); -} - -/** Free-callback function to free a 'struct pbuf_custom_ref', called by - * pbuf_free. */ -static void -ip6_frag_free_pbuf_custom(struct pbuf *p) -{ - struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; - LWIP_ASSERT("pcr != NULL", pcr != NULL); - LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); - if (pcr->original != NULL) { - pbuf_free(pcr->original); - } - ip6_frag_free_pbuf_custom_ref(pcr); -} -#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ - -/** - * Fragment an IPv6 datagram if too large for the netif or path MTU. - * - * Chop the datagram in MTU sized chunks and send them in order - * by pointing PBUF_REFs into p - * - * @param p ipv6 packet to send - * @param netif the netif on which to send - * @param dest destination ipv6 address to which to send - * - * @return ERR_OK if sent successfully, err_t otherwise - */ -err_t -ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest) -{ - struct ip6_hdr *original_ip6hdr; - struct ip6_hdr *ip6hdr; - struct ip6_frag_hdr *frag_hdr; - struct pbuf *rambuf; -#if !LWIP_NETIF_TX_SINGLE_PBUF - struct pbuf *newpbuf; - u16_t newpbuflen = 0; - u16_t left_to_copy; -#endif - static u32_t identification; - u16_t left, cop; - const u16_t mtu = nd6_get_destination_mtu(dest, netif); - const u16_t nfb = (u16_t)((mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK); - u16_t fragment_offset = 0; - u16_t last; - u16_t poff = IP6_HLEN; - - identification++; - - original_ip6hdr = (struct ip6_hdr *)p->payload; - - /* @todo we assume there are no options in the unfragmentable part (IPv6 header). */ - LWIP_ASSERT("p->tot_len >= IP6_HLEN", p->tot_len >= IP6_HLEN); - left = (u16_t)(p->tot_len - IP6_HLEN); - - while (left) { - last = (left <= nfb); - - /* Fill this fragment */ - cop = last ? left : nfb; - -#if LWIP_NETIF_TX_SINGLE_PBUF - rambuf = pbuf_alloc(PBUF_IP, cop + IP6_FRAG_HLEN, PBUF_RAM); - if (rambuf == NULL) { - IP6_FRAG_STATS_INC(ip6_frag.memerr); - return ERR_MEM; - } - LWIP_ASSERT("this needs a pbuf in one piece!", - (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); - poff += pbuf_copy_partial(p, (u8_t*)rambuf->payload + IP6_FRAG_HLEN, cop, poff); - /* make room for the IP header */ - if (pbuf_add_header(rambuf, IP6_HLEN)) { - pbuf_free(rambuf); - IP6_FRAG_STATS_INC(ip6_frag.memerr); - return ERR_MEM; - } - /* fill in the IP header */ - SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); - ip6hdr = (struct ip6_hdr *)rambuf->payload; - frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); -#else - /* When not using a static buffer, create a chain of pbufs. - * The first will be a PBUF_RAM holding the link, IPv6, and Fragment header. - * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, - * but limited to the size of an mtu. - */ - rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM); - if (rambuf == NULL) { - IP6_FRAG_STATS_INC(ip6_frag.memerr); - return ERR_MEM; - } - LWIP_ASSERT("this needs a pbuf in one piece!", - (p->len >= (IP6_HLEN))); - SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); - ip6hdr = (struct ip6_hdr *)rambuf->payload; - frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); - - /* Can just adjust p directly for needed offset. */ - p->payload = (u8_t *)p->payload + poff; - p->len = (u16_t)(p->len - poff); - p->tot_len = (u16_t)(p->tot_len - poff); - - left_to_copy = cop; - while (left_to_copy) { - struct pbuf_custom_ref *pcr; - newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; - /* Is this pbuf already empty? */ - if (!newpbuflen) { - p = p->next; - continue; - } - pcr = ip6_frag_alloc_pbuf_custom_ref(); - if (pcr == NULL) { - pbuf_free(rambuf); - IP6_FRAG_STATS_INC(ip6_frag.memerr); - return ERR_MEM; - } - /* Mirror this pbuf, although we might not need all of it. */ - newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); - if (newpbuf == NULL) { - ip6_frag_free_pbuf_custom_ref(pcr); - pbuf_free(rambuf); - IP6_FRAG_STATS_INC(ip6_frag.memerr); - return ERR_MEM; - } - pbuf_ref(p); - pcr->original = p; - pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom; - - /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain - * so that it is removed when pbuf_dechain is later called on rambuf. - */ - pbuf_cat(rambuf, newpbuf); - left_to_copy = (u16_t)(left_to_copy - newpbuflen); - if (left_to_copy) { - p = p->next; - } - } - poff = newpbuflen; -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - - /* Set headers */ - frag_hdr->_nexth = original_ip6hdr->_nexth; - frag_hdr->reserved = 0; - frag_hdr->_fragment_offset = lwip_htons((u16_t)((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG))); - frag_hdr->_identification = lwip_htonl(identification); - - IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT); - IP6H_PLEN_SET(ip6hdr, (u16_t)(cop + IP6_FRAG_HLEN)); - - /* No need for separate header pbuf - we allowed room for it in rambuf - * when allocated. - */ - IP6_FRAG_STATS_INC(ip6_frag.xmit); - netif->output_ip6(netif, rambuf, dest); - - /* Unfortunately we can't reuse rambuf - the hardware may still be - * using the buffer. Instead we free it (and the ensuing chain) and - * recreate it next time round the loop. If we're lucky the hardware - * will have already sent the packet, the free will really free, and - * there will be zero memory penalty. - */ - - pbuf_free(rambuf); - left = (u16_t)(left - cop); - fragment_offset = (u16_t)(fragment_offset + cop); - } - return ERR_OK; -} - -#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ diff --git a/core/c/core/ipv6/mld6.c b/core/c/core/ipv6/mld6.c deleted file mode 100755 index db1d09a..0000000 --- a/core/c/core/ipv6/mld6.c +++ /dev/null @@ -1,626 +0,0 @@ -/** - * @file - * Multicast listener discovery - * - * @defgroup mld6 MLD6 - * @ingroup ip6 - * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. - * No support for MLDv2.\n - * Note: The allnodes (ff01::1, ff02::1) group is assumed be received by your - * netif since it must always be received for correct IPv6 operation (e.g. SLAAC). - * Ensure the netif filters are configured accordingly!\n - * The netif flags also need NETIF_FLAG_MLD6 flag set to enable MLD6 on a - * netif ("netif->flags |= NETIF_FLAG_MLD6;").\n - * To be called from TCPIP thread. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -/* Based on igmp.c implementation of igmp v2 protocol */ - -#include "lwip/opt.h" - -#if LWIP_IPV6 && LWIP_IPV6_MLD /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/mld6.h" -#include "lwip/prot/mld6.h" -#include "lwip/icmp6.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/ip.h" -#include "lwip/inet_chksum.h" -#include "lwip/pbuf.h" -#include "lwip/netif.h" -#include "lwip/memp.h" -#include "lwip/stats.h" - -#include - - -/* - * MLD constants - */ -#define MLD6_HL 1 -#define MLD6_JOIN_DELAYING_MEMBER_TMR_MS (500) - -#define MLD6_GROUP_NON_MEMBER 0 -#define MLD6_GROUP_DELAYING_MEMBER 1 -#define MLD6_GROUP_IDLE_MEMBER 2 - -/* Forward declarations. */ -static struct mld_group *mld6_new_group(struct netif *ifp, const ip6_addr_t *addr); -static err_t mld6_remove_group(struct netif *netif, struct mld_group *group); -static void mld6_delayed_report(struct mld_group *group, u16_t maxresp); -static void mld6_send(struct netif *netif, struct mld_group *group, u8_t type); - - -/** - * Stop MLD processing on interface - * - * @param netif network interface on which stop MLD processing - */ -err_t -mld6_stop(struct netif *netif) -{ - struct mld_group *group = netif_mld6_data(netif); - - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, NULL); - - while (group != NULL) { - struct mld_group *next = group->next; /* avoid use-after-free below */ - - /* disable the group at the MAC level */ - if (netif->mld_mac_filter != NULL) { - netif->mld_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER); - } - - /* free group */ - memp_free(MEMP_MLD6_GROUP, group); - - /* move to "next" */ - group = next; - } - return ERR_OK; -} - -/** - * Report MLD memberships for this interface - * - * @param netif network interface on which report MLD memberships - */ -void -mld6_report_groups(struct netif *netif) -{ - struct mld_group *group = netif_mld6_data(netif); - - while (group != NULL) { - mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); - group = group->next; - } -} - -/** - * Search for a group that is joined on a netif - * - * @param ifp the network interface for which to look - * @param addr the group ipv6 address to search for - * @return a struct mld_group* if the group has been found, - * NULL if the group wasn't found. - */ -struct mld_group * -mld6_lookfor_group(struct netif *ifp, const ip6_addr_t *addr) -{ - struct mld_group *group = netif_mld6_data(ifp); - - while (group != NULL) { - if (ip6_addr_cmp(&(group->group_address), addr)) { - return group; - } - group = group->next; - } - - return NULL; -} - - -/** - * create a new group - * - * @param ifp the network interface for which to create - * @param addr the new group ipv6 - * @return a struct mld_group*, - * NULL on memory error. - */ -static struct mld_group * -mld6_new_group(struct netif *ifp, const ip6_addr_t *addr) -{ - struct mld_group *group; - - group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP); - if (group != NULL) { - ip6_addr_set(&(group->group_address), addr); - group->timer = 0; /* Not running */ - group->group_state = MLD6_GROUP_IDLE_MEMBER; - group->last_reporter_flag = 0; - group->use = 0; - group->next = netif_mld6_data(ifp); - - netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group); - } - - return group; -} - -/** - * Remove a group from the mld_group_list, but do not free it yet - * - * @param group the group to remove - * @return ERR_OK if group was removed from the list, an err_t otherwise - */ -static err_t -mld6_remove_group(struct netif *netif, struct mld_group *group) -{ - err_t err = ERR_OK; - - /* Is it the first group? */ - if (netif_mld6_data(netif) == group) { - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group->next); - } else { - /* look for group further down the list */ - struct mld_group *tmpGroup; - for (tmpGroup = netif_mld6_data(netif); tmpGroup != NULL; tmpGroup = tmpGroup->next) { - if (tmpGroup->next == group) { - tmpGroup->next = group->next; - break; - } - } - /* Group not find group */ - if (tmpGroup == NULL) { - err = ERR_ARG; - } - } - - return err; -} - - -/** - * Process an input MLD message. Called by icmp6_input. - * - * @param p the mld packet, p->payload pointing to the icmpv6 header - * @param inp the netif on which this packet was received - */ -void -mld6_input(struct pbuf *p, struct netif *inp) -{ - struct mld_header *mld_hdr; - struct mld_group *group; - - MLD6_STATS_INC(mld6.recv); - - /* Check that mld header fits in packet. */ - if (p->len < sizeof(struct mld_header)) { - /* @todo debug message */ - pbuf_free(p); - MLD6_STATS_INC(mld6.lenerr); - MLD6_STATS_INC(mld6.drop); - return; - } - - mld_hdr = (struct mld_header *)p->payload; - - switch (mld_hdr->type) { - case ICMP6_TYPE_MLQ: /* Multicast listener query. */ - /* Is it a general query? */ - if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) && - ip6_addr_isany(&(mld_hdr->multicast_address))) { - MLD6_STATS_INC(mld6.rx_general); - /* Report all groups, except all nodes group, and if-local groups. */ - group = netif_mld6_data(inp); - while (group != NULL) { - if ((!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) && - (!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) { - mld6_delayed_report(group, mld_hdr->max_resp_delay); - } - group = group->next; - } - } else { - /* Have we joined this group? - * We use IP6 destination address to have a memory aligned copy. - * mld_hdr->multicast_address should be the same. */ - MLD6_STATS_INC(mld6.rx_group); - group = mld6_lookfor_group(inp, ip6_current_dest_addr()); - if (group != NULL) { - /* Schedule a report. */ - mld6_delayed_report(group, mld_hdr->max_resp_delay); - } - } - break; /* ICMP6_TYPE_MLQ */ - case ICMP6_TYPE_MLR: /* Multicast listener report. */ - /* Have we joined this group? - * We use IP6 destination address to have a memory aligned copy. - * mld_hdr->multicast_address should be the same. */ - MLD6_STATS_INC(mld6.rx_report); - group = mld6_lookfor_group(inp, ip6_current_dest_addr()); - if (group != NULL) { - /* If we are waiting to report, cancel it. */ - if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { - group->timer = 0; /* stopped */ - group->group_state = MLD6_GROUP_IDLE_MEMBER; - group->last_reporter_flag = 0; - } - } - break; /* ICMP6_TYPE_MLR */ - case ICMP6_TYPE_MLD: /* Multicast listener done. */ - /* Do nothing, router will query us. */ - break; /* ICMP6_TYPE_MLD */ - default: - MLD6_STATS_INC(mld6.proterr); - MLD6_STATS_INC(mld6.drop); - break; - } - - pbuf_free(p); -} - -/** - * @ingroup mld6 - * Join a group on one or all network interfaces. - * - * If the group is to be joined on all interfaces, the given group address must - * not have a zone set (i.e., it must have its zone index set to IP6_NO_ZONE). - * If the group is to be joined on one particular interface, the given group - * address may or may not have a zone set. - * - * @param srcaddr ipv6 address (zoned) of the network interface which should - * join a new group. If IP6_ADDR_ANY6, join on all netifs - * @param groupaddr the ipv6 address of the group to join (possibly but not - * necessarily zoned) - * @return ERR_OK if group was joined on the netif(s), an err_t otherwise - */ -err_t -mld6_joingroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) -{ - err_t err = ERR_VAL; /* no matching interface */ - struct netif *netif; - - LWIP_ASSERT_CORE_LOCKED(); - - /* loop through netif's */ - NETIF_FOREACH(netif) { - /* Should we join this interface ? */ - if (ip6_addr_isany(srcaddr) || - netif_get_ip6_addr_match(netif, srcaddr) >= 0) { - err = mld6_joingroup_netif(netif, groupaddr); - if (err != ERR_OK) { - return err; - } - } - } - - return err; -} - -/** - * @ingroup mld6 - * Join a group on a network interface. - * - * @param netif the network interface which should join a new group. - * @param groupaddr the ipv6 address of the group to join (possibly but not - * necessarily zoned) - * @return ERR_OK if group was joined on the netif, an err_t otherwise - */ -err_t -mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr) -{ - struct mld_group *group; -#if LWIP_IPV6_SCOPES - ip6_addr_t ip6addr; - - /* If the address has a particular scope but no zone set, use the netif to - * set one now. Within the mld6 module, all addresses are properly zoned. */ - if (ip6_addr_lacks_zone(groupaddr, IP6_MULTICAST)) { - ip6_addr_set(&ip6addr, groupaddr); - ip6_addr_assign_zone(&ip6addr, IP6_MULTICAST, netif); - groupaddr = &ip6addr; - } - IP6_ADDR_ZONECHECK_NETIF(groupaddr, netif); -#endif /* LWIP_IPV6_SCOPES */ - - LWIP_ASSERT_CORE_LOCKED(); - - /* find group or create a new one if not found */ - group = mld6_lookfor_group(netif, groupaddr); - - if (group == NULL) { - /* Joining a new group. Create a new group entry. */ - group = mld6_new_group(netif, groupaddr); - if (group == NULL) { - return ERR_MEM; - } - - /* Activate this address on the MAC layer. */ - if (netif->mld_mac_filter != NULL) { - netif->mld_mac_filter(netif, groupaddr, NETIF_ADD_MAC_FILTER); - } - - /* Report our membership. */ - MLD6_STATS_INC(mld6.tx_report); - mld6_send(netif, group, ICMP6_TYPE_MLR); - mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); - } - - /* Increment group use */ - group->use++; - return ERR_OK; -} - -/** - * @ingroup mld6 - * Leave a group on a network interface. - * - * Zoning of address follows the same rules as @ref mld6_joingroup. - * - * @param srcaddr ipv6 address (zoned) of the network interface which should - * leave the group. If IP6_ADDR_ANY6, leave on all netifs - * @param groupaddr the ipv6 address of the group to leave (possibly, but not - * necessarily zoned) - * @return ERR_OK if group was left on the netif(s), an err_t otherwise - */ -err_t -mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) -{ - err_t err = ERR_VAL; /* no matching interface */ - struct netif *netif; - - LWIP_ASSERT_CORE_LOCKED(); - - /* loop through netif's */ - NETIF_FOREACH(netif) { - /* Should we leave this interface ? */ - if (ip6_addr_isany(srcaddr) || - netif_get_ip6_addr_match(netif, srcaddr) >= 0) { - err_t res = mld6_leavegroup_netif(netif, groupaddr); - if (err != ERR_OK) { - /* Store this result if we have not yet gotten a success */ - err = res; - } - } - } - - return err; -} - -/** - * @ingroup mld6 - * Leave a group on a network interface. - * - * @param netif the network interface which should leave the group. - * @param groupaddr the ipv6 address of the group to leave (possibly, but not - * necessarily zoned) - * @return ERR_OK if group was left on the netif, an err_t otherwise - */ -err_t -mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr) -{ - struct mld_group *group; -#if LWIP_IPV6_SCOPES - ip6_addr_t ip6addr; - - if (ip6_addr_lacks_zone(groupaddr, IP6_MULTICAST)) { - ip6_addr_set(&ip6addr, groupaddr); - ip6_addr_assign_zone(&ip6addr, IP6_MULTICAST, netif); - groupaddr = &ip6addr; - } - IP6_ADDR_ZONECHECK_NETIF(groupaddr, netif); -#endif /* LWIP_IPV6_SCOPES */ - - LWIP_ASSERT_CORE_LOCKED(); - - /* find group */ - group = mld6_lookfor_group(netif, groupaddr); - - if (group != NULL) { - /* Leave if there is no other use of the group */ - if (group->use <= 1) { - /* Remove the group from the list */ - mld6_remove_group(netif, group); - - /* If we are the last reporter for this group */ - if (group->last_reporter_flag) { - MLD6_STATS_INC(mld6.tx_leave); - mld6_send(netif, group, ICMP6_TYPE_MLD); - } - - /* Disable the group at the MAC level */ - if (netif->mld_mac_filter != NULL) { - netif->mld_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER); - } - - /* free group struct */ - memp_free(MEMP_MLD6_GROUP, group); - } else { - /* Decrement group use */ - group->use--; - } - - /* Left group */ - return ERR_OK; - } - - /* Group not found */ - return ERR_VAL; -} - - -/** - * Periodic timer for mld processing. Must be called every - * MLD6_TMR_INTERVAL milliseconds (100). - * - * When a delaying member expires, a membership report is sent. - */ -void -mld6_tmr(void) -{ - struct netif *netif; - - NETIF_FOREACH(netif) { - struct mld_group *group = netif_mld6_data(netif); - - while (group != NULL) { - if (group->timer > 0) { - group->timer--; - if (group->timer == 0) { - /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */ - if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { - MLD6_STATS_INC(mld6.tx_report); - mld6_send(netif, group, ICMP6_TYPE_MLR); - group->group_state = MLD6_GROUP_IDLE_MEMBER; - } - } - } - group = group->next; - } - } -} - -/** - * Schedule a delayed membership report for a group - * - * @param group the mld_group for which "delaying" membership report - * should be sent - * @param maxresp_in the max resp delay provided in the query - */ -static void -mld6_delayed_report(struct mld_group *group, u16_t maxresp_in) -{ - /* Convert maxresp from milliseconds to tmr ticks */ - u16_t maxresp = maxresp_in / MLD6_TMR_INTERVAL; - if (maxresp == 0) { - maxresp = 1; - } - -#ifdef LWIP_RAND - /* Randomize maxresp. (if LWIP_RAND is supported) */ - maxresp = (u16_t)(LWIP_RAND() % maxresp); - if (maxresp == 0) { - maxresp = 1; - } -#endif /* LWIP_RAND */ - - /* Apply timer value if no report has been scheduled already. */ - if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) || - ((group->group_state == MLD6_GROUP_DELAYING_MEMBER) && - ((group->timer == 0) || (maxresp < group->timer)))) { - group->timer = maxresp; - group->group_state = MLD6_GROUP_DELAYING_MEMBER; - } -} - -/** - * Send a MLD message (report or done). - * - * An IPv6 hop-by-hop options header with a router alert option - * is prepended. - * - * @param group the group to report or quit - * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done) - */ -static void -mld6_send(struct netif *netif, struct mld_group *group, u8_t type) -{ - struct mld_header *mld_hdr; - struct pbuf *p; - const ip6_addr_t *src_addr; - - /* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */ - p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + MLD6_HBH_HLEN, PBUF_RAM); - if (p == NULL) { - MLD6_STATS_INC(mld6.memerr); - return; - } - - /* Move to make room for Hop-by-hop options header. */ - if (pbuf_remove_header(p, MLD6_HBH_HLEN)) { - pbuf_free(p); - MLD6_STATS_INC(mld6.lenerr); - return; - } - - /* Select our source address. */ - if (!ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) { - /* This is a special case, when we are performing duplicate address detection. - * We must join the multicast group, but we don't have a valid address yet. */ - src_addr = IP6_ADDR_ANY6; - } else { - /* Use link-local address as source address. */ - src_addr = netif_ip6_addr(netif, 0); - } - - /* MLD message header pointer. */ - mld_hdr = (struct mld_header *)p->payload; - - /* Set fields. */ - mld_hdr->type = type; - mld_hdr->code = 0; - mld_hdr->chksum = 0; - mld_hdr->max_resp_delay = 0; - mld_hdr->reserved = 0; - ip6_addr_copy_to_packed(mld_hdr->multicast_address, group->group_address); - -#if CHECKSUM_GEN_ICMP6 - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { - mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, - src_addr, &(group->group_address)); - } -#endif /* CHECKSUM_GEN_ICMP6 */ - - /* Add hop-by-hop headers options: router alert with MLD value. */ - ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD); - - if (type == ICMP6_TYPE_MLR) { - /* Remember we were the last to report */ - group->last_reporter_flag = 1; - } - - /* Send the packet out. */ - MLD6_STATS_INC(mld6.xmit); - ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address), - MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, netif); - pbuf_free(p); -} - -#endif /* LWIP_IPV6 */ diff --git a/core/c/core/ipv6/nd6.c b/core/c/core/ipv6/nd6.c deleted file mode 100755 index 5deb3f1..0000000 --- a/core/c/core/ipv6/nd6.c +++ /dev/null @@ -1,2434 +0,0 @@ -/** - * @file - * - * Neighbor discovery and stateless address autoconfiguration for IPv6. - * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 - * (Address autoconfiguration). - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#include "lwip/opt.h" - -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/nd6.h" -#include "lwip/priv/nd6_priv.h" -#include "lwip/prot/nd6.h" -#include "lwip/prot/icmp6.h" -#include "lwip/pbuf.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/inet_chksum.h" -#include "lwip/netif.h" -#include "lwip/icmp6.h" -#include "lwip/mld6.h" -#include "lwip/dhcp6.h" -#include "lwip/ip.h" -#include "lwip/stats.h" -#include "lwip/dns.h" - -#include - -#ifdef LWIP_HOOK_FILENAME -#include LWIP_HOOK_FILENAME -#endif - -#if LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK -#error LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK -#endif - -/* Router tables. */ -struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS]; -struct nd6_destination_cache_entry destination_cache[LWIP_ND6_NUM_DESTINATIONS]; -struct nd6_prefix_list_entry prefix_list[LWIP_ND6_NUM_PREFIXES]; -struct nd6_router_list_entry default_router_list[LWIP_ND6_NUM_ROUTERS]; - -/* Default values, can be updated by a RA message. */ -u32_t reachable_time = LWIP_ND6_REACHABLE_TIME; -u32_t retrans_timer = LWIP_ND6_RETRANS_TIMER; /* @todo implement this value in timer */ - -/* Index for cache entries. */ -static u8_t nd6_cached_neighbor_index; -static netif_addr_idx_t nd6_cached_destination_index; - -/* Multicast address holder. */ -static ip6_addr_t multicast_address; - -static u8_t nd6_tmr_rs_reduction; - -/* Static buffer to parse RA packet options */ -union ra_options { - struct lladdr_option lladdr; - struct mtu_option mtu; - struct prefix_option prefix; -#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS - struct rdnss_option rdnss; -#endif -}; -static union ra_options nd6_ra_buffer; - -/* Forward declarations. */ -static s8_t nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr); -static s8_t nd6_new_neighbor_cache_entry(void); -static void nd6_free_neighbor_cache_entry(s8_t i); -static s16_t nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr); -static s16_t nd6_new_destination_cache_entry(void); -static int nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif); -static s8_t nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif); -static s8_t nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif); -static s8_t nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif); -static s8_t nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif); -static s8_t nd6_new_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif); -static s8_t nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif); -static err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf *q); - -#define ND6_SEND_FLAG_MULTICAST_DEST 0x01 -#define ND6_SEND_FLAG_ALLNODES_DEST 0x02 -#define ND6_SEND_FLAG_ANY_SRC 0x04 -static void nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags); -static void nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags); -static void nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags); -#if LWIP_IPV6_SEND_ROUTER_SOLICIT -static err_t nd6_send_rs(struct netif *netif); -#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ - -#if LWIP_ND6_QUEUEING -static void nd6_free_q(struct nd6_q_entry *q); -#else /* LWIP_ND6_QUEUEING */ -#define nd6_free_q(q) pbuf_free(q) -#endif /* LWIP_ND6_QUEUEING */ -static void nd6_send_q(s8_t i); - - -/** - * A local address has been determined to be a duplicate. Take the appropriate - * action(s) on the address and the interface as a whole. - * - * @param netif the netif that owns the address - * @param addr_idx the index of the address detected to be a duplicate - */ -static void -nd6_duplicate_addr_detected(struct netif *netif, s8_t addr_idx) -{ - - /* Mark the address as duplicate, but leave its lifetimes alone. If this was - * a manually assigned address, it will remain in existence as duplicate, and - * as such be unusable for any practical purposes until manual intervention. - * If this was an autogenerated address, the address will follow normal - * expiration rules, and thus disappear once its valid lifetime expires. */ - netif_ip6_addr_set_state(netif, addr_idx, IP6_ADDR_DUPLICATED); - -#if LWIP_IPV6_AUTOCONFIG - /* If the affected address was the link-local address that we use to generate - * all other addresses, then we should not continue to use those derived - * addresses either, so mark them as duplicate as well. For autoconfig-only - * setups, this will make the interface effectively unusable, approaching the - * intention of RFC 4862 Sec. 5.4.5. @todo implement the full requirements */ - if (addr_idx == 0) { - s8_t i; - for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) && - !netif_ip6_addr_isstatic(netif, i)) { - netif_ip6_addr_set_state(netif, i, IP6_ADDR_DUPLICATED); - } - } - } -#endif /* LWIP_IPV6_AUTOCONFIG */ -} - -#if LWIP_IPV6_AUTOCONFIG -/** - * We received a router advertisement that contains a prefix with the - * autoconfiguration flag set. Add or update an associated autogenerated - * address. - * - * @param netif the netif on which the router advertisement arrived - * @param prefix_opt a pointer to the prefix option data - * @param prefix_addr an aligned copy of the prefix address - */ -static void -nd6_process_autoconfig_prefix(struct netif *netif, - struct prefix_option *prefix_opt, const ip6_addr_t *prefix_addr) -{ - ip6_addr_t ip6addr; - u32_t valid_life, pref_life; - u8_t addr_state; - s8_t i, free_idx; - - /* The caller already checks RFC 4862 Sec. 5.5.3 points (a) and (b). We do - * the rest, starting with checks for (c) and (d) here. */ - valid_life = lwip_htonl(prefix_opt->valid_lifetime); - pref_life = lwip_htonl(prefix_opt->preferred_lifetime); - if (pref_life > valid_life || prefix_opt->prefix_length != 64) { - return; /* silently ignore this prefix for autoconfiguration purposes */ - } - - /* If an autogenerated address already exists for this prefix, update its - * lifetimes. An address is considered autogenerated if 1) it is not static - * (i.e., manually assigned), and 2) there is an advertised autoconfiguration - * prefix for it (the one we are processing here). This does not necessarily - * exclude the possibility that the address was actually assigned by, say, - * DHCPv6. If that distinction becomes important in the future, more state - * must be kept. As explained elsewhere we also update lifetimes of tentative - * and duplicate addresses. Skip address slot 0 (the link-local address). */ - for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - addr_state = netif_ip6_addr_state(netif, i); - if (!ip6_addr_isinvalid(addr_state) && !netif_ip6_addr_isstatic(netif, i) && - ip6_addr_netcmp(prefix_addr, netif_ip6_addr(netif, i))) { - /* Update the valid lifetime, as per RFC 4862 Sec. 5.5.3 point (e). - * The valid lifetime will never drop to zero as a result of this. */ - u32_t remaining_life = netif_ip6_addr_valid_life(netif, i); - if (valid_life > ND6_2HRS || valid_life > remaining_life) { - netif_ip6_addr_set_valid_life(netif, i, valid_life); - } else if (remaining_life > ND6_2HRS) { - netif_ip6_addr_set_valid_life(netif, i, ND6_2HRS); - } - LWIP_ASSERT("bad valid lifetime", !netif_ip6_addr_isstatic(netif, i)); - /* Update the preferred lifetime. No bounds checks are needed here. In - * rare cases the advertisement may un-deprecate the address, though. - * Deprecation is left to the timer code where it is handled anyway. */ - if (pref_life > 0 && addr_state == IP6_ADDR_DEPRECATED) { - netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED); - } - netif_ip6_addr_set_pref_life(netif, i, pref_life); - return; /* there should be at most one matching address */ - } - } - - /* No autogenerated address exists for this prefix yet. See if we can add a - * new one. However, if IPv6 autoconfiguration is administratively disabled, - * do not generate new addresses, but do keep updating lifetimes for existing - * addresses. Also, when adding new addresses, we must protect explicitly - * against a valid lifetime of zero, because again, we use that as a special - * value. The generated address would otherwise expire immediately anyway. - * Finally, the original link-local address must be usable at all. We start - * creating addresses even if the link-local address is still in tentative - * state though, and deal with the fallout of that upon DAD collision. */ - addr_state = netif_ip6_addr_state(netif, 0); - if (!netif->ip6_autoconfig_enabled || valid_life == IP6_ADDR_LIFE_STATIC || - ip6_addr_isinvalid(addr_state) || ip6_addr_isduplicated(addr_state)) { - return; - } - - /* Construct the new address that we intend to use, and then see if that - * address really does not exist. It might have been added manually, after - * all. As a side effect, find a free slot. Note that we cannot use - * netif_add_ip6_address() here, as it would return ERR_OK if the address - * already did exist, resulting in that address being given lifetimes. */ - IP6_ADDR(&ip6addr, prefix_addr->addr[0], prefix_addr->addr[1], - netif_ip6_addr(netif, 0)->addr[2], netif_ip6_addr(netif, 0)->addr[3]); - ip6_addr_assign_zone(&ip6addr, IP6_UNICAST, netif); - - free_idx = 0; - for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) { - if (ip6_addr_cmp(&ip6addr, netif_ip6_addr(netif, i))) { - return; /* formed address already exists */ - } - } else if (free_idx == 0) { - free_idx = i; - } - } - if (free_idx == 0) { - return; /* no address slots available, try again on next advertisement */ - } - - /* Assign the new address to the interface. */ - ip_addr_copy_from_ip6(netif->ip6_addr[free_idx], ip6addr); - netif_ip6_addr_set_valid_life(netif, free_idx, valid_life); - netif_ip6_addr_set_pref_life(netif, free_idx, pref_life); - netif_ip6_addr_set_state(netif, free_idx, IP6_ADDR_TENTATIVE); -} -#endif /* LWIP_IPV6_AUTOCONFIG */ - -/** - * Process an incoming neighbor discovery message - * - * @param p the nd packet, p->payload pointing to the icmpv6 header - * @param inp the netif on which this packet was received - */ -void -nd6_input(struct pbuf *p, struct netif *inp) -{ - u8_t msg_type; - s8_t i; - s16_t dest_idx; - - ND6_STATS_INC(nd6.recv); - - msg_type = *((u8_t *)p->payload); - switch (msg_type) { - case ICMP6_TYPE_NA: /* Neighbor Advertisement. */ - { - struct na_header *na_hdr; - struct lladdr_option *lladdr_opt; - ip6_addr_t target_address; - - /* Check that na header fits in packet. */ - if (p->len < (sizeof(struct na_header))) { - /* @todo debug message */ - pbuf_free(p); - ND6_STATS_INC(nd6.lenerr); - ND6_STATS_INC(nd6.drop); - return; - } - - na_hdr = (struct na_header *)p->payload; - - /* Create an aligned, zoned copy of the target address. */ - ip6_addr_copy_from_packed(target_address, na_hdr->target_address); - ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp); - - /* Check a subset of the other RFC 4861 Sec. 7.1.2 requirements. */ - if (IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || na_hdr->code != 0 || - ip6_addr_ismulticast(&target_address)) { - pbuf_free(p); - ND6_STATS_INC(nd6.proterr); - ND6_STATS_INC(nd6.drop); - return; - } - - /* @todo RFC MUST: if IP destination is multicast, Solicited flag is zero */ - /* @todo RFC MUST: all included options have a length greater than zero */ - - /* Unsolicited NA?*/ - if (ip6_addr_ismulticast(ip6_current_dest_addr())) { - /* This is an unsolicited NA. - * link-layer changed? - * part of DAD mechanism? */ - -#if LWIP_IPV6_DUP_DETECT_ATTEMPTS - /* If the target address matches this netif, it is a DAD response. */ - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && - !ip6_addr_isduplicated(netif_ip6_addr_state(inp, i)) && - ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { - /* We are using a duplicate address. */ - nd6_duplicate_addr_detected(inp, i); - - pbuf_free(p); - return; - } - } -#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */ - - /* Check that link-layer address option also fits in packet. */ - if (p->len < (sizeof(struct na_header) + 2)) { - /* @todo debug message */ - pbuf_free(p); - ND6_STATS_INC(nd6.lenerr); - ND6_STATS_INC(nd6.drop); - return; - } - - lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); - - if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) { - /* @todo debug message */ - pbuf_free(p); - ND6_STATS_INC(nd6.lenerr); - ND6_STATS_INC(nd6.drop); - return; - } - - /* This is an unsolicited NA, most likely there was a LLADDR change. */ - i = nd6_find_neighbor_cache_entry(&target_address); - if (i >= 0) { - if (na_hdr->flags & ND6_FLAG_OVERRIDE) { - MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); - } - } - } else { - /* This is a solicited NA. - * neighbor address resolution response? - * neighbor unreachability detection response? */ - - /* Find the cache entry corresponding to this na. */ - i = nd6_find_neighbor_cache_entry(&target_address); - if (i < 0) { - /* We no longer care about this target address. drop it. */ - pbuf_free(p); - return; - } - - /* Update cache entry. */ - if ((na_hdr->flags & ND6_FLAG_OVERRIDE) || - (neighbor_cache[i].state == ND6_INCOMPLETE)) { - /* Check that link-layer address option also fits in packet. */ - if (p->len < (sizeof(struct na_header) + 2)) { - /* @todo debug message */ - pbuf_free(p); - ND6_STATS_INC(nd6.lenerr); - ND6_STATS_INC(nd6.drop); - return; - } - - lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); - - if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) { - /* @todo debug message */ - pbuf_free(p); - ND6_STATS_INC(nd6.lenerr); - ND6_STATS_INC(nd6.drop); - return; - } - - MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); - } - - neighbor_cache[i].netif = inp; - neighbor_cache[i].state = ND6_REACHABLE; - neighbor_cache[i].counter.reachable_time = reachable_time; - - /* Send queued packets, if any. */ - if (neighbor_cache[i].q != NULL) { - nd6_send_q(i); - } - } - - break; /* ICMP6_TYPE_NA */ - } - case ICMP6_TYPE_NS: /* Neighbor solicitation. */ - { - struct ns_header *ns_hdr; - struct lladdr_option *lladdr_opt; - ip6_addr_t target_address; - u8_t accepted; - - /* Check that ns header fits in packet. */ - if (p->len < sizeof(struct ns_header)) { - /* @todo debug message */ - pbuf_free(p); - ND6_STATS_INC(nd6.lenerr); - ND6_STATS_INC(nd6.drop); - return; - } - - ns_hdr = (struct ns_header *)p->payload; - - /* Create an aligned, zoned copy of the target address. */ - ip6_addr_copy_from_packed(target_address, ns_hdr->target_address); - ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp); - - /* Check a subset of the other RFC 4861 Sec. 7.1.1 requirements. */ - if (IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || ns_hdr->code != 0 || - ip6_addr_ismulticast(&target_address)) { - pbuf_free(p); - ND6_STATS_INC(nd6.proterr); - ND6_STATS_INC(nd6.drop); - return; - } - - /* @todo RFC MUST: all included options have a length greater than zero */ - /* @todo RFC MUST: if IP source is 'any', destination is solicited-node multicast address */ - /* @todo RFC MUST: if IP source is 'any', there is no source LL address option */ - - /* Check if there is a link-layer address provided. Only point to it if in this buffer. */ - if (p->len >= (sizeof(struct ns_header) + 2)) { - lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); - if (p->len < (sizeof(struct ns_header) + (lladdr_opt->length << 3))) { - lladdr_opt = NULL; - } - } else { - lladdr_opt = NULL; - } - - /* Check if the target address is configured on the receiving netif. */ - accepted = 0; - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { - if ((ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) || - (ip6_addr_istentative(netif_ip6_addr_state(inp, i)) && - ip6_addr_isany(ip6_current_src_addr()))) && - ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { - accepted = 1; - break; - } - } - - /* NS not for us? */ - if (!accepted) { - pbuf_free(p); - return; - } - - /* Check for ANY address in src (DAD algorithm). */ - if (ip6_addr_isany(ip6_current_src_addr())) { - /* Sender is validating this address. */ - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { - if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && - ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { - /* Send a NA back so that the sender does not use this address. */ - nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST); - if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) { - /* We shouldn't use this address either. */ - nd6_duplicate_addr_detected(inp, i); - } - } - } - } else { - /* Sender is trying to resolve our address. */ - /* Verify that they included their own link-layer address. */ - if (lladdr_opt == NULL) { - /* Not a valid message. */ - pbuf_free(p); - ND6_STATS_INC(nd6.proterr); - ND6_STATS_INC(nd6.drop); - return; - } - - i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); - if (i>= 0) { - /* We already have a record for the solicitor. */ - if (neighbor_cache[i].state == ND6_INCOMPLETE) { - neighbor_cache[i].netif = inp; - MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); - - /* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ - neighbor_cache[i].state = ND6_DELAY; - neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; - } - } else { - /* Add their IPv6 address and link-layer address to neighbor cache. - * We will need it at least to send a unicast NA message, but most - * likely we will also be communicating with this node soon. */ - i = nd6_new_neighbor_cache_entry(); - if (i < 0) { - /* We couldn't assign a cache entry for this neighbor. - * we won't be able to reply. drop it. */ - pbuf_free(p); - ND6_STATS_INC(nd6.memerr); - return; - } - neighbor_cache[i].netif = inp; - MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); - ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); - - /* Receiving a message does not prove reachability: only in one direction. - * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ - neighbor_cache[i].state = ND6_DELAY; - neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; - } - - /* Send back a NA for us. Allocate the reply pbuf. */ - nd6_send_na(inp, &target_address, ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE); - } - - break; /* ICMP6_TYPE_NS */ - } - case ICMP6_TYPE_RA: /* Router Advertisement. */ - { - struct ra_header *ra_hdr; - u8_t *buffer; /* Used to copy options. */ - u16_t offset; -#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS - /* There can be multiple RDNSS options per RA */ - u8_t rdnss_server_idx = 0; -#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */ - - /* Check that RA header fits in packet. */ - if (p->len < sizeof(struct ra_header)) { - /* @todo debug message */ - pbuf_free(p); - ND6_STATS_INC(nd6.lenerr); - ND6_STATS_INC(nd6.drop); - return; - } - - ra_hdr = (struct ra_header *)p->payload; - - /* Check a subset of the other RFC 4861 Sec. 6.1.2 requirements. */ - if (!ip6_addr_islinklocal(ip6_current_src_addr()) || - IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || ra_hdr->code != 0) { - pbuf_free(p); - ND6_STATS_INC(nd6.proterr); - ND6_STATS_INC(nd6.drop); - return; - } - - /* @todo RFC MUST: all included options have a length greater than zero */ - - /* If we are sending RS messages, stop. */ -#if LWIP_IPV6_SEND_ROUTER_SOLICIT - /* ensure at least one solicitation is sent (see RFC 4861, ch. 6.3.7) */ - if ((inp->rs_count < LWIP_ND6_MAX_MULTICAST_SOLICIT) || - (nd6_send_rs(inp) == ERR_OK)) { - inp->rs_count = 0; - } else { - inp->rs_count = 1; - } -#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ - - /* Get the matching default router entry. */ - i = nd6_get_router(ip6_current_src_addr(), inp); - if (i < 0) { - /* Create a new router entry. */ - i = nd6_new_router(ip6_current_src_addr(), inp); - } - - if (i < 0) { - /* Could not create a new router entry. */ - pbuf_free(p); - ND6_STATS_INC(nd6.memerr); - return; - } - - /* Re-set invalidation timer. */ - default_router_list[i].invalidation_timer = lwip_htons(ra_hdr->router_lifetime); - - /* Re-set default timer values. */ -#if LWIP_ND6_ALLOW_RA_UPDATES - if (ra_hdr->retrans_timer > 0) { - retrans_timer = lwip_htonl(ra_hdr->retrans_timer); - } - if (ra_hdr->reachable_time > 0) { - reachable_time = lwip_htonl(ra_hdr->reachable_time); - } -#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ - - /* @todo set default hop limit... */ - /* ra_hdr->current_hop_limit;*/ - - /* Update flags in local entry (incl. preference). */ - default_router_list[i].flags = ra_hdr->flags; - -#if LWIP_IPV6_DHCP6 - /* Trigger DHCPv6 if enabled */ - dhcp6_nd6_ra_trigger(inp, ra_hdr->flags & ND6_RA_FLAG_MANAGED_ADDR_CONFIG, - ra_hdr->flags & ND6_RA_FLAG_OTHER_CONFIG); -#endif - - /* Offset to options. */ - offset = sizeof(struct ra_header); - - /* Process each option. */ - while ((p->tot_len - offset) >= 2) { - u8_t option_type; - u16_t option_len; - int option_len8 = pbuf_try_get_at(p, offset + 1); - if (option_len8 <= 0) { - /* read beyond end or zero length */ - goto lenerr_drop_free_return; - } - option_len = ((u8_t)option_len8) << 3; - if (option_len > p->tot_len - offset) { - /* short packet (option does not fit in) */ - goto lenerr_drop_free_return; - } - if (p->len == p->tot_len) { - /* no need to copy from contiguous pbuf */ - buffer = &((u8_t*)p->payload)[offset]; - } else { - /* check if this option fits into our buffer */ - if (option_len > sizeof(nd6_ra_buffer)) { - option_type = pbuf_get_at(p, offset); - /* invalid option length */ - if (option_type != ND6_OPTION_TYPE_RDNSS) { - goto lenerr_drop_free_return; - } - /* we allow RDNSS option to be longer - we'll just drop some servers */ - option_len = sizeof(nd6_ra_buffer); - } - buffer = (u8_t*)&nd6_ra_buffer; - option_len = pbuf_copy_partial(p, &nd6_ra_buffer, option_len, offset); - } - option_type = buffer[0]; - switch (option_type) { - case ND6_OPTION_TYPE_SOURCE_LLADDR: - { - struct lladdr_option *lladdr_opt; - if (option_len < sizeof(struct lladdr_option)) { - goto lenerr_drop_free_return; - } - lladdr_opt = (struct lladdr_option *)buffer; - if ((default_router_list[i].neighbor_entry != NULL) && - (default_router_list[i].neighbor_entry->state == ND6_INCOMPLETE)) { - SMEMCPY(default_router_list[i].neighbor_entry->lladdr, lladdr_opt->addr, inp->hwaddr_len); - default_router_list[i].neighbor_entry->state = ND6_REACHABLE; - default_router_list[i].neighbor_entry->counter.reachable_time = reachable_time; - } - break; - } - case ND6_OPTION_TYPE_MTU: - { - struct mtu_option *mtu_opt; - u32_t mtu32; - if (option_len < sizeof(struct mtu_option)) { - goto lenerr_drop_free_return; - } - mtu_opt = (struct mtu_option *)buffer; - mtu32 = lwip_htonl(mtu_opt->mtu); - if ((mtu32 >= 1280) && (mtu32 <= 0xffff)) { -#if LWIP_ND6_ALLOW_RA_UPDATES - if (inp->mtu) { - /* don't set the mtu for IPv6 higher than the netif driver supports */ - inp->mtu6 = LWIP_MIN(inp->mtu, (u16_t)mtu32); - } else { - inp->mtu6 = (u16_t)mtu32; - } -#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ - } - break; - } - case ND6_OPTION_TYPE_PREFIX_INFO: - { - struct prefix_option *prefix_opt; - ip6_addr_t prefix_addr; - if (option_len < sizeof(struct prefix_option)) { - goto lenerr_drop_free_return; - } - - prefix_opt = (struct prefix_option *)buffer; - - /* Get a memory-aligned copy of the prefix. */ - ip6_addr_copy_from_packed(prefix_addr, prefix_opt->prefix); - ip6_addr_assign_zone(&prefix_addr, IP6_UNICAST, inp); - - if (!ip6_addr_islinklocal(&prefix_addr)) { - if ((prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) && - (prefix_opt->prefix_length == 64)) { - /* Add to on-link prefix list. */ - u32_t valid_life; - s8_t prefix; - - valid_life = lwip_htonl(prefix_opt->valid_lifetime); - - /* find cache entry for this prefix. */ - prefix = nd6_get_onlink_prefix(&prefix_addr, inp); - if (prefix < 0 && valid_life > 0) { - /* Create a new cache entry. */ - prefix = nd6_new_onlink_prefix(&prefix_addr, inp); - } - if (prefix >= 0) { - prefix_list[prefix].invalidation_timer = valid_life; - } - } -#if LWIP_IPV6_AUTOCONFIG - if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) { - /* Perform processing for autoconfiguration. */ - nd6_process_autoconfig_prefix(inp, prefix_opt, &prefix_addr); - } -#endif /* LWIP_IPV6_AUTOCONFIG */ - } - - break; - } - case ND6_OPTION_TYPE_ROUTE_INFO: - /* @todo implement preferred routes. - struct route_option * route_opt; - route_opt = (struct route_option *)buffer;*/ - - break; -#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS - case ND6_OPTION_TYPE_RDNSS: - { - u8_t num, n; - u16_t copy_offset = offset + SIZEOF_RDNSS_OPTION_BASE; - struct rdnss_option * rdnss_opt; - if (option_len < SIZEOF_RDNSS_OPTION_BASE) { - goto lenerr_drop_free_return; - } - - rdnss_opt = (struct rdnss_option *)buffer; - num = (rdnss_opt->length - 1) / 2; - for (n = 0; (rdnss_server_idx < DNS_MAX_SERVERS) && (n < num); n++) { - ip_addr_t rdnss_address; - - /* Copy directly from pbuf to get an aligned, zoned copy of the prefix. */ - if (pbuf_copy_partial(p, &rdnss_address, sizeof(ip6_addr_p_t), copy_offset) == sizeof(ip6_addr_p_t)) { - IP_SET_TYPE_VAL(rdnss_address, IPADDR_TYPE_V6); - ip6_addr_assign_zone(ip_2_ip6(&rdnss_address), IP6_UNKNOWN, inp); - - if (htonl(rdnss_opt->lifetime) > 0) { - /* TODO implement Lifetime > 0 */ - dns_setserver(rdnss_server_idx++, &rdnss_address); - } else { - /* TODO implement DNS removal in dns.c */ - u8_t s; - for (s = 0; s < DNS_MAX_SERVERS; s++) { - const ip_addr_t *addr = dns_getserver(s); - if(ip_addr_cmp(addr, &rdnss_address)) { - dns_setserver(s, NULL); - } - } - } - } - } - break; - } -#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */ - default: - /* Unrecognized option, abort. */ - ND6_STATS_INC(nd6.proterr); - break; - } - /* option length is checked earlier to be non-zero to make sure loop ends */ - offset += 8 * (u8_t)option_len8; - } - - break; /* ICMP6_TYPE_RA */ - } - case ICMP6_TYPE_RD: /* Redirect */ - { - struct redirect_header *redir_hdr; - struct lladdr_option *lladdr_opt; - ip6_addr_t destination_address, target_address; - - /* Check that Redir header fits in packet. */ - if (p->len < sizeof(struct redirect_header)) { - /* @todo debug message */ - pbuf_free(p); - ND6_STATS_INC(nd6.lenerr); - ND6_STATS_INC(nd6.drop); - return; - } - - redir_hdr = (struct redirect_header *)p->payload; - - /* Create an aligned, zoned copy of the destination address. */ - ip6_addr_copy_from_packed(destination_address, redir_hdr->destination_address); - ip6_addr_assign_zone(&destination_address, IP6_UNICAST, inp); - - /* Check a subset of the other RFC 4861 Sec. 8.1 requirements. */ - if (!ip6_addr_islinklocal(ip6_current_src_addr()) || - IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || - redir_hdr->code != 0 || ip6_addr_ismulticast(&destination_address)) { - pbuf_free(p); - ND6_STATS_INC(nd6.proterr); - ND6_STATS_INC(nd6.drop); - return; - } - - /* @todo RFC MUST: IP source address equals first-hop router for destination_address */ - /* @todo RFC MUST: ICMP target address is either link-local address or same as destination_address */ - /* @todo RFC MUST: all included options have a length greater than zero */ - - if (p->len >= (sizeof(struct redirect_header) + 2)) { - lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct redirect_header)); - if (p->len < (sizeof(struct redirect_header) + (lladdr_opt->length << 3))) { - lladdr_opt = NULL; - } - } else { - lladdr_opt = NULL; - } - - /* Find dest address in cache */ - dest_idx = nd6_find_destination_cache_entry(&destination_address); - if (dest_idx < 0) { - /* Destination not in cache, drop packet. */ - pbuf_free(p); - return; - } - - /* Create an aligned, zoned copy of the target address. */ - ip6_addr_copy_from_packed(target_address, redir_hdr->target_address); - ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp); - - /* Set the new target address. */ - ip6_addr_copy(destination_cache[dest_idx].next_hop_addr, target_address); - - /* If Link-layer address of other router is given, try to add to neighbor cache. */ - if (lladdr_opt != NULL) { - if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) { - i = nd6_find_neighbor_cache_entry(&target_address); - if (i < 0) { - i = nd6_new_neighbor_cache_entry(); - if (i >= 0) { - neighbor_cache[i].netif = inp; - MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); - ip6_addr_copy(neighbor_cache[i].next_hop_address, target_address); - - /* Receiving a message does not prove reachability: only in one direction. - * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ - neighbor_cache[i].state = ND6_DELAY; - neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; - } - } - if (i >= 0) { - if (neighbor_cache[i].state == ND6_INCOMPLETE) { - MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); - /* Receiving a message does not prove reachability: only in one direction. - * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ - neighbor_cache[i].state = ND6_DELAY; - neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; - } - } - } - } - break; /* ICMP6_TYPE_RD */ - } - case ICMP6_TYPE_PTB: /* Packet too big */ - { - struct icmp6_hdr *icmp6hdr; /* Packet too big message */ - struct ip6_hdr *ip6hdr; /* IPv6 header of the packet which caused the error */ - u32_t pmtu; - ip6_addr_t destination_address; - - /* Check that ICMPv6 header + IPv6 header fit in payload */ - if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) { - /* drop short packets */ - pbuf_free(p); - ND6_STATS_INC(nd6.lenerr); - ND6_STATS_INC(nd6.drop); - return; - } - - icmp6hdr = (struct icmp6_hdr *)p->payload; - ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr)); - - /* Create an aligned, zoned copy of the destination address. */ - ip6_addr_copy_from_packed(destination_address, ip6hdr->dest); - ip6_addr_assign_zone(&destination_address, IP6_UNKNOWN, inp); - - /* Look for entry in destination cache. */ - dest_idx = nd6_find_destination_cache_entry(&destination_address); - if (dest_idx < 0) { - /* Destination not in cache, drop packet. */ - pbuf_free(p); - return; - } - - /* Change the Path MTU. */ - pmtu = lwip_htonl(icmp6hdr->data); - destination_cache[dest_idx].pmtu = (u16_t)LWIP_MIN(pmtu, 0xFFFF); - - break; /* ICMP6_TYPE_PTB */ - } - - default: - ND6_STATS_INC(nd6.proterr); - ND6_STATS_INC(nd6.drop); - break; /* default */ - } - - pbuf_free(p); - return; -lenerr_drop_free_return: - ND6_STATS_INC(nd6.lenerr); - ND6_STATS_INC(nd6.drop); - pbuf_free(p); -} - - -/** - * Periodic timer for Neighbor discovery functions: - * - * - Update neighbor reachability states - * - Update destination cache entries age - * - Update invalidation timers of default routers and on-link prefixes - * - Update lifetimes of our addresses - * - Perform duplicate address detection (DAD) for our addresses - * - Send router solicitations - */ -void -nd6_tmr(void) -{ - s8_t i; - struct netif *netif; - - /* Process neighbor entries. */ - for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { - switch (neighbor_cache[i].state) { - case ND6_INCOMPLETE: - if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) && - (!neighbor_cache[i].isrouter)) { - /* Retries exceeded. */ - nd6_free_neighbor_cache_entry(i); - } else { - /* Send a NS for this entry. */ - neighbor_cache[i].counter.probes_sent++; - nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST); - } - break; - case ND6_REACHABLE: - /* Send queued packets, if any are left. Should have been sent already. */ - if (neighbor_cache[i].q != NULL) { - nd6_send_q(i); - } - if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) { - /* Change to stale state. */ - neighbor_cache[i].state = ND6_STALE; - neighbor_cache[i].counter.stale_time = 0; - } else { - neighbor_cache[i].counter.reachable_time -= ND6_TMR_INTERVAL; - } - break; - case ND6_STALE: - neighbor_cache[i].counter.stale_time++; - break; - case ND6_DELAY: - if (neighbor_cache[i].counter.delay_time <= 1) { - /* Change to PROBE state. */ - neighbor_cache[i].state = ND6_PROBE; - neighbor_cache[i].counter.probes_sent = 0; - } else { - neighbor_cache[i].counter.delay_time--; - } - break; - case ND6_PROBE: - if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) && - (!neighbor_cache[i].isrouter)) { - /* Retries exceeded. */ - nd6_free_neighbor_cache_entry(i); - } else { - /* Send a NS for this entry. */ - neighbor_cache[i].counter.probes_sent++; - nd6_send_neighbor_cache_probe(&neighbor_cache[i], 0); - } - break; - case ND6_NO_ENTRY: - default: - /* Do nothing. */ - break; - } - } - - /* Process destination entries. */ - for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { - destination_cache[i].age++; - } - - /* Process router entries. */ - for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { - if (default_router_list[i].neighbor_entry != NULL) { - /* Active entry. */ - if (default_router_list[i].invalidation_timer <= ND6_TMR_INTERVAL / 1000) { - /* No more than 1 second remaining. Clear this entry. Also clear any of - * its destination cache entries, as per RFC 4861 Sec. 5.3 and 6.3.5. */ - s8_t j; - for (j = 0; j < LWIP_ND6_NUM_DESTINATIONS; j++) { - if (ip6_addr_cmp(&destination_cache[j].next_hop_addr, - &default_router_list[i].neighbor_entry->next_hop_address)) { - ip6_addr_set_any(&destination_cache[j].destination_addr); - } - } - default_router_list[i].neighbor_entry->isrouter = 0; - default_router_list[i].neighbor_entry = NULL; - default_router_list[i].invalidation_timer = 0; - default_router_list[i].flags = 0; - } else { - default_router_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; - } - } - } - - /* Process prefix entries. */ - for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { - if (prefix_list[i].netif != NULL) { - if (prefix_list[i].invalidation_timer <= ND6_TMR_INTERVAL / 1000) { - /* Entry timed out, remove it */ - prefix_list[i].invalidation_timer = 0; - prefix_list[i].netif = NULL; - } else { - prefix_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; - } - } - } - - /* Process our own addresses, updating address lifetimes and/or DAD state. */ - NETIF_FOREACH(netif) { - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { - u8_t addr_state; -#if LWIP_IPV6_ADDRESS_LIFETIMES - /* Step 1: update address lifetimes (valid and preferred). */ - addr_state = netif_ip6_addr_state(netif, i); - /* RFC 4862 is not entirely clear as to whether address lifetimes affect - * tentative addresses, and is even less clear as to what should happen - * with duplicate addresses. We choose to track and update lifetimes for - * both those types, although for different reasons: - * - for tentative addresses, the line of thought of Sec. 5.7 combined - * with the potentially long period that an address may be in tentative - * state (due to the interface being down) suggests that lifetimes - * should be independent of external factors which would include DAD; - * - for duplicate addresses, retiring them early could result in a new - * but unwanted attempt at marking them as valid, while retiring them - * late/never could clog up address slots on the netif. - * As a result, we may end up expiring addresses of either type here. - */ - if (!ip6_addr_isinvalid(addr_state) && - !netif_ip6_addr_isstatic(netif, i)) { - u32_t life = netif_ip6_addr_valid_life(netif, i); - if (life <= ND6_TMR_INTERVAL / 1000) { - /* The address has expired. */ - netif_ip6_addr_set_valid_life(netif, i, 0); - netif_ip6_addr_set_pref_life(netif, i, 0); - netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID); - } else { - if (!ip6_addr_life_isinfinite(life)) { - life -= ND6_TMR_INTERVAL / 1000; - LWIP_ASSERT("bad valid lifetime", life != IP6_ADDR_LIFE_STATIC); - netif_ip6_addr_set_valid_life(netif, i, life); - } - /* The address is still here. Update the preferred lifetime too. */ - life = netif_ip6_addr_pref_life(netif, i); - if (life <= ND6_TMR_INTERVAL / 1000) { - /* This case must also trigger if 'life' was already zero, so as to - * deal correctly with advertised preferred-lifetime reductions. */ - netif_ip6_addr_set_pref_life(netif, i, 0); - if (addr_state == IP6_ADDR_PREFERRED) - netif_ip6_addr_set_state(netif, i, IP6_ADDR_DEPRECATED); - } else if (!ip6_addr_life_isinfinite(life)) { - life -= ND6_TMR_INTERVAL / 1000; - netif_ip6_addr_set_pref_life(netif, i, life); - } - } - } - /* The address state may now have changed, so reobtain it next. */ -#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ - /* Step 2: update DAD state. */ - addr_state = netif_ip6_addr_state(netif, i); - if (ip6_addr_istentative(addr_state)) { - if ((addr_state & IP6_ADDR_TENTATIVE_COUNT_MASK) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) { - /* No NA received in response. Mark address as valid. For dynamic - * addresses with an expired preferred lifetime, the state is set to - * deprecated right away. That should almost never happen, though. */ - addr_state = IP6_ADDR_PREFERRED; -#if LWIP_IPV6_ADDRESS_LIFETIMES - if (!netif_ip6_addr_isstatic(netif, i) && - netif_ip6_addr_pref_life(netif, i) == 0) { - addr_state = IP6_ADDR_DEPRECATED; - } -#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ - netif_ip6_addr_set_state(netif, i, addr_state); - } else if (netif_is_up(netif) && netif_is_link_up(netif)) { - /* tentative: set next state by increasing by one */ - netif_ip6_addr_set_state(netif, i, addr_state + 1); - /* Send a NS for this address. Use the unspecified address as source - * address in all cases (RFC 4862 Sec. 5.4.2), not in the least - * because as it is, we only consider multicast replies for DAD. */ - nd6_send_ns(netif, netif_ip6_addr(netif, i), - ND6_SEND_FLAG_MULTICAST_DEST | ND6_SEND_FLAG_ANY_SRC); - } - } - } - } - -#if LWIP_IPV6_SEND_ROUTER_SOLICIT - /* Send router solicitation messages, if necessary. */ - if (!nd6_tmr_rs_reduction) { - nd6_tmr_rs_reduction = (ND6_RTR_SOLICITATION_INTERVAL / ND6_TMR_INTERVAL) - 1; - NETIF_FOREACH(netif) { - if ((netif->rs_count > 0) && netif_is_up(netif) && - netif_is_link_up(netif) && - !ip6_addr_isinvalid(netif_ip6_addr_state(netif, 0)) && - !ip6_addr_isduplicated(netif_ip6_addr_state(netif, 0))) { - if (nd6_send_rs(netif) == ERR_OK) { - netif->rs_count--; - } - } - } - } else { - nd6_tmr_rs_reduction--; - } -#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ - -} - -/** Send a neighbor solicitation message for a specific neighbor cache entry - * - * @param entry the neightbor cache entry for wich to send the message - * @param flags one of ND6_SEND_FLAG_* - */ -static void -nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags) -{ - nd6_send_ns(entry->netif, &entry->next_hop_address, flags); -} - -/** - * Send a neighbor solicitation message - * - * @param netif the netif on which to send the message - * @param target_addr the IPv6 target address for the ND message - * @param flags one of ND6_SEND_FLAG_* - */ -static void -nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags) -{ - struct ns_header *ns_hdr; - struct pbuf *p; - const ip6_addr_t *src_addr; - u16_t lladdr_opt_len; - - LWIP_ASSERT("target address is required", target_addr != NULL); - - if (!(flags & ND6_SEND_FLAG_ANY_SRC) && - ip6_addr_isvalid(netif_ip6_addr_state(netif,0))) { - /* Use link-local address as source address. */ - src_addr = netif_ip6_addr(netif, 0); - /* calculate option length (in 8-byte-blocks) */ - lladdr_opt_len = ((netif->hwaddr_len + 2) + 7) >> 3; - } else { - src_addr = IP6_ADDR_ANY6; - /* Option "MUST NOT be included when the source IP address is the unspecified address." */ - lladdr_opt_len = 0; - } - - /* Allocate a packet. */ - p = pbuf_alloc(PBUF_IP, sizeof(struct ns_header) + (lladdr_opt_len << 3), PBUF_RAM); - if (p == NULL) { - ND6_STATS_INC(nd6.memerr); - return; - } - - /* Set fields. */ - ns_hdr = (struct ns_header *)p->payload; - - ns_hdr->type = ICMP6_TYPE_NS; - ns_hdr->code = 0; - ns_hdr->chksum = 0; - ns_hdr->reserved = 0; - ip6_addr_copy_to_packed(ns_hdr->target_address, *target_addr); - - if (lladdr_opt_len != 0) { - struct lladdr_option *lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); - lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; - lladdr_opt->length = (u8_t)lladdr_opt_len; - SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); - } - - /* Generate the solicited node address for the target address. */ - if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { - ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); - ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); - target_addr = &multicast_address; - } - -#if CHECKSUM_GEN_ICMP6 - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { - ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, - target_addr); - } -#endif /* CHECKSUM_GEN_ICMP6 */ - - /* Send the packet out. */ - ND6_STATS_INC(nd6.xmit); - ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, target_addr, - ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif); - pbuf_free(p); -} - -/** - * Send a neighbor advertisement message - * - * @param netif the netif on which to send the message - * @param target_addr the IPv6 target address for the ND message - * @param flags one of ND6_SEND_FLAG_* - */ -static void -nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags) -{ - struct na_header *na_hdr; - struct lladdr_option *lladdr_opt; - struct pbuf *p; - const ip6_addr_t *src_addr; - const ip6_addr_t *dest_addr; - u16_t lladdr_opt_len; - - LWIP_ASSERT("target address is required", target_addr != NULL); - - /* Use link-local address as source address. */ - /* src_addr = netif_ip6_addr(netif, 0); */ - /* Use target address as source address. */ - src_addr = target_addr; - - /* Allocate a packet. */ - lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); - p = pbuf_alloc(PBUF_IP, sizeof(struct na_header) + (lladdr_opt_len << 3), PBUF_RAM); - if (p == NULL) { - ND6_STATS_INC(nd6.memerr); - return; - } - - /* Set fields. */ - na_hdr = (struct na_header *)p->payload; - lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); - - na_hdr->type = ICMP6_TYPE_NA; - na_hdr->code = 0; - na_hdr->chksum = 0; - na_hdr->flags = flags & 0xf0; - na_hdr->reserved[0] = 0; - na_hdr->reserved[1] = 0; - na_hdr->reserved[2] = 0; - ip6_addr_copy_to_packed(na_hdr->target_address, *target_addr); - - lladdr_opt->type = ND6_OPTION_TYPE_TARGET_LLADDR; - lladdr_opt->length = (u8_t)lladdr_opt_len; - SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); - - /* Generate the solicited node address for the target address. */ - if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { - ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); - ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); - dest_addr = &multicast_address; - } else if (flags & ND6_SEND_FLAG_ALLNODES_DEST) { - ip6_addr_set_allnodes_linklocal(&multicast_address); - ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); - dest_addr = &multicast_address; - } else { - dest_addr = ip6_current_src_addr(); - } - -#if CHECKSUM_GEN_ICMP6 - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { - na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, - dest_addr); - } -#endif /* CHECKSUM_GEN_ICMP6 */ - - /* Send the packet out. */ - ND6_STATS_INC(nd6.xmit); - ip6_output_if(p, src_addr, dest_addr, - ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif); - pbuf_free(p); -} - -#if LWIP_IPV6_SEND_ROUTER_SOLICIT -/** - * Send a router solicitation message - * - * @param netif the netif on which to send the message - */ -static err_t -nd6_send_rs(struct netif *netif) -{ - struct rs_header *rs_hdr; - struct lladdr_option *lladdr_opt; - struct pbuf *p; - const ip6_addr_t *src_addr; - err_t err; - u16_t lladdr_opt_len = 0; - - /* Link-local source address, or unspecified address? */ - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) { - src_addr = netif_ip6_addr(netif, 0); - } else { - src_addr = IP6_ADDR_ANY6; - } - - /* Generate the all routers target address. */ - ip6_addr_set_allrouters_linklocal(&multicast_address); - ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); - - /* Allocate a packet. */ - if (src_addr != IP6_ADDR_ANY6) { - lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); - } - p = pbuf_alloc(PBUF_IP, sizeof(struct rs_header) + (lladdr_opt_len << 3), PBUF_RAM); - if (p == NULL) { - ND6_STATS_INC(nd6.memerr); - return ERR_BUF; - } - - /* Set fields. */ - rs_hdr = (struct rs_header *)p->payload; - - rs_hdr->type = ICMP6_TYPE_RS; - rs_hdr->code = 0; - rs_hdr->chksum = 0; - rs_hdr->reserved = 0; - - if (src_addr != IP6_ADDR_ANY6) { - /* Include our hw address. */ - lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct rs_header)); - lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; - lladdr_opt->length = (u8_t)lladdr_opt_len; - SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); - } - -#if CHECKSUM_GEN_ICMP6 - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { - rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, - &multicast_address); - } -#endif /* CHECKSUM_GEN_ICMP6 */ - - /* Send the packet out. */ - ND6_STATS_INC(nd6.xmit); - - err = ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, &multicast_address, - ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif); - pbuf_free(p); - - return err; -} -#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ - -/** - * Search for a neighbor cache entry - * - * @param ip6addr the IPv6 address of the neighbor - * @return The neighbor cache entry index that matched, -1 if no - * entry is found - */ -static s8_t -nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr) -{ - s8_t i; - for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { - if (ip6_addr_cmp(ip6addr, &(neighbor_cache[i].next_hop_address))) { - return i; - } - } - return -1; -} - -/** - * Create a new neighbor cache entry. - * - * If no unused entry is found, will try to recycle an old entry - * according to ad-hoc "age" heuristic. - * - * @return The neighbor cache entry index that was created, -1 if no - * entry could be created - */ -static s8_t -nd6_new_neighbor_cache_entry(void) -{ - s8_t i; - s8_t j; - u32_t time; - - - /* First, try to find an empty entry. */ - for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { - if (neighbor_cache[i].state == ND6_NO_ENTRY) { - return i; - } - } - - /* We need to recycle an entry. in general, do not recycle if it is a router. */ - - /* Next, try to find a Stale entry. */ - for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { - if ((neighbor_cache[i].state == ND6_STALE) && - (!neighbor_cache[i].isrouter)) { - nd6_free_neighbor_cache_entry(i); - return i; - } - } - - /* Next, try to find a Probe entry. */ - for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { - if ((neighbor_cache[i].state == ND6_PROBE) && - (!neighbor_cache[i].isrouter)) { - nd6_free_neighbor_cache_entry(i); - return i; - } - } - - /* Next, try to find a Delayed entry. */ - for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { - if ((neighbor_cache[i].state == ND6_DELAY) && - (!neighbor_cache[i].isrouter)) { - nd6_free_neighbor_cache_entry(i); - return i; - } - } - - /* Next, try to find the oldest reachable entry. */ - time = 0xfffffffful; - j = -1; - for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { - if ((neighbor_cache[i].state == ND6_REACHABLE) && - (!neighbor_cache[i].isrouter)) { - if (neighbor_cache[i].counter.reachable_time < time) { - j = i; - time = neighbor_cache[i].counter.reachable_time; - } - } - } - if (j >= 0) { - nd6_free_neighbor_cache_entry(j); - return j; - } - - /* Next, find oldest incomplete entry without queued packets. */ - time = 0; - j = -1; - for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { - if ( - (neighbor_cache[i].q == NULL) && - (neighbor_cache[i].state == ND6_INCOMPLETE) && - (!neighbor_cache[i].isrouter)) { - if (neighbor_cache[i].counter.probes_sent >= time) { - j = i; - time = neighbor_cache[i].counter.probes_sent; - } - } - } - if (j >= 0) { - nd6_free_neighbor_cache_entry(j); - return j; - } - - /* Next, find oldest incomplete entry with queued packets. */ - time = 0; - j = -1; - for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { - if ((neighbor_cache[i].state == ND6_INCOMPLETE) && - (!neighbor_cache[i].isrouter)) { - if (neighbor_cache[i].counter.probes_sent >= time) { - j = i; - time = neighbor_cache[i].counter.probes_sent; - } - } - } - if (j >= 0) { - nd6_free_neighbor_cache_entry(j); - return j; - } - - /* No more entries to try. */ - return -1; -} - -/** - * Will free any resources associated with a neighbor cache - * entry, and will mark it as unused. - * - * @param i the neighbor cache entry index to free - */ -static void -nd6_free_neighbor_cache_entry(s8_t i) -{ - if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { - return; - } - if (neighbor_cache[i].isrouter) { - /* isrouter needs to be cleared before deleting a neighbor cache entry */ - return; - } - - /* Free any queued packets. */ - if (neighbor_cache[i].q != NULL) { - nd6_free_q(neighbor_cache[i].q); - neighbor_cache[i].q = NULL; - } - - neighbor_cache[i].state = ND6_NO_ENTRY; - neighbor_cache[i].isrouter = 0; - neighbor_cache[i].netif = NULL; - neighbor_cache[i].counter.reachable_time = 0; - ip6_addr_set_zero(&(neighbor_cache[i].next_hop_address)); -} - -/** - * Search for a destination cache entry - * - * @param ip6addr the IPv6 address of the destination - * @return The destination cache entry index that matched, -1 if no - * entry is found - */ -static s16_t -nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr) -{ - s16_t i; - - IP6_ADDR_ZONECHECK(ip6addr); - - for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { - if (ip6_addr_cmp(ip6addr, &(destination_cache[i].destination_addr))) { - return i; - } - } - return -1; -} - -/** - * Create a new destination cache entry. If no unused entry is found, - * will recycle oldest entry. - * - * @return The destination cache entry index that was created, -1 if no - * entry was created - */ -static s16_t -nd6_new_destination_cache_entry(void) -{ - s16_t i, j; - u32_t age; - - /* Find an empty entry. */ - for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { - if (ip6_addr_isany(&(destination_cache[i].destination_addr))) { - return i; - } - } - - /* Find oldest entry. */ - age = 0; - j = LWIP_ND6_NUM_DESTINATIONS - 1; - for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { - if (destination_cache[i].age > age) { - j = i; - } - } - - return j; -} - -/** - * Clear the destination cache. - * - * This operation may be necessary for consistency in the light of changing - * local addresses and/or use of the gateway hook. - */ -void -nd6_clear_destination_cache(void) -{ - int i; - - for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { - ip6_addr_set_any(&destination_cache[i].destination_addr); - } -} - -/** - * Determine whether an address matches an on-link prefix or the subnet of a - * statically assigned address. - * - * @param ip6addr the IPv6 address to match - * @return 1 if the address is on-link, 0 otherwise - */ -static int -nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif) -{ - s8_t i; - - /* Check to see if the address matches an on-link prefix. */ - for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { - if ((prefix_list[i].netif == netif) && - (prefix_list[i].invalidation_timer > 0) && - ip6_addr_netcmp(ip6addr, &(prefix_list[i].prefix))) { - return 1; - } - } - /* Check to see if address prefix matches a manually configured (= static) - * address. Static addresses have an implied /64 subnet assignment. Dynamic - * addresses (from autoconfiguration) have no implied subnet assignment, and - * are thus effectively /128 assignments. See RFC 5942 for more on this. */ - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - netif_ip6_addr_isstatic(netif, i) && - ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) { - return 1; - } - } - return 0; -} - -/** - * Select a default router for a destination. - * - * This function is used both for routing and for finding a next-hop target for - * a packet. In the former case, the given netif is NULL, and the returned - * router entry must be for a netif suitable for sending packets (up, link up). - * In the latter case, the given netif is not NULL and restricts router choice. - * - * @param ip6addr the destination address - * @param netif the netif for the outgoing packet, if known - * @return the default router entry index, or -1 if no suitable - * router is found - */ -static s8_t -nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif) -{ - struct netif *router_netif; - s8_t i, j, valid_router; - static s8_t last_router; - - LWIP_UNUSED_ARG(ip6addr); /* @todo match preferred routes!! (must implement ND6_OPTION_TYPE_ROUTE_INFO) */ - - /* @todo: implement default router preference */ - - /* Look for valid routers. A reachable router is preferred. */ - valid_router = -1; - for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { - /* Is the router netif both set and apppropriate? */ - if (default_router_list[i].neighbor_entry != NULL) { - router_netif = default_router_list[i].neighbor_entry->netif; - if ((router_netif != NULL) && (netif != NULL ? netif == router_netif : - (netif_is_up(router_netif) && netif_is_link_up(router_netif)))) { - /* Is the router valid, i.e., reachable or probably reachable as per - * RFC 4861 Sec. 6.3.6? Note that we will never return a router that - * has no neighbor cache entry, due to the netif association tests. */ - if (default_router_list[i].neighbor_entry->state != ND6_INCOMPLETE) { - /* Is the router known to be reachable? */ - if (default_router_list[i].neighbor_entry->state == ND6_REACHABLE) { - return i; /* valid and reachable - done! */ - } else if (valid_router < 0) { - valid_router = i; /* valid but not known to be reachable */ - } - } - } - } - } - if (valid_router >= 0) { - return valid_router; - } - - /* Look for any router for which we have any information at all. */ - /* last_router is used for round-robin selection of incomplete routers, as - * recommended in RFC 4861 Sec. 6.3.6 point (2). Advance only when picking a - * route, to select the same router as next-hop target in the common case. */ - if ((netif == NULL) && (++last_router >= LWIP_ND6_NUM_ROUTERS)) { - last_router = 0; - } - i = last_router; - for (j = 0; j < LWIP_ND6_NUM_ROUTERS; j++) { - if (default_router_list[i].neighbor_entry != NULL) { - router_netif = default_router_list[i].neighbor_entry->netif; - if ((router_netif != NULL) && (netif != NULL ? netif == router_netif : - (netif_is_up(router_netif) && netif_is_link_up(router_netif)))) { - return i; - } - } - if (++i >= LWIP_ND6_NUM_ROUTERS) { - i = 0; - } - } - - /* no suitable router found. */ - return -1; -} - -/** - * Find a router-announced route to the given destination. This route may be - * based on an on-link prefix or a default router. - * - * If a suitable route is found, the returned netif is guaranteed to be in a - * suitable state (up, link up) to be used for packet transmission. - * - * @param ip6addr the destination IPv6 address - * @return the netif to use for the destination, or NULL if none found - */ -struct netif * -nd6_find_route(const ip6_addr_t *ip6addr) -{ - struct netif *netif; - s8_t i; - - /* @todo decide if it makes sense to check the destination cache first */ - - /* Check if there is a matching on-link prefix. There may be multiple - * matches. Pick the first one that is associated with a suitable netif. */ - for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { - netif = prefix_list[i].netif; - if ((netif != NULL) && ip6_addr_netcmp(&prefix_list[i].prefix, ip6addr) && - netif_is_up(netif) && netif_is_link_up(netif)) { - return netif; - } - } - - /* No on-link prefix match. Find a router that can forward the packet. */ - i = nd6_select_router(ip6addr, NULL); - if (i >= 0) { - LWIP_ASSERT("selected router must have a neighbor entry", - default_router_list[i].neighbor_entry != NULL); - return default_router_list[i].neighbor_entry->netif; - } - - return NULL; -} - -/** - * Find an entry for a default router. - * - * @param router_addr the IPv6 address of the router - * @param netif the netif on which the router is found, if known - * @return the index of the router entry, or -1 if not found - */ -static s8_t -nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif) -{ - s8_t i; - - IP6_ADDR_ZONECHECK_NETIF(router_addr, netif); - - /* Look for router. */ - for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { - if ((default_router_list[i].neighbor_entry != NULL) && - ((netif != NULL) ? netif == default_router_list[i].neighbor_entry->netif : 1) && - ip6_addr_cmp(router_addr, &(default_router_list[i].neighbor_entry->next_hop_address))) { - return i; - } - } - - /* router not found. */ - return -1; -} - -/** - * Create a new entry for a default router. - * - * @param router_addr the IPv6 address of the router - * @param netif the netif on which the router is connected, if known - * @return the index on the router table, or -1 if could not be created - */ -static s8_t -nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif) -{ - s8_t router_index; - s8_t free_router_index; - s8_t neighbor_index; - - IP6_ADDR_ZONECHECK_NETIF(router_addr, netif); - - /* Do we have a neighbor entry for this router? */ - neighbor_index = nd6_find_neighbor_cache_entry(router_addr); - if (neighbor_index < 0) { - /* Create a neighbor entry for this router. */ - neighbor_index = nd6_new_neighbor_cache_entry(); - if (neighbor_index < 0) { - /* Could not create neighbor entry for this router. */ - return -1; - } - ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr); - neighbor_cache[neighbor_index].netif = netif; - neighbor_cache[neighbor_index].q = NULL; - neighbor_cache[neighbor_index].state = ND6_INCOMPLETE; - neighbor_cache[neighbor_index].counter.probes_sent = 1; - nd6_send_neighbor_cache_probe(&neighbor_cache[neighbor_index], ND6_SEND_FLAG_MULTICAST_DEST); - } - - /* Mark neighbor as router. */ - neighbor_cache[neighbor_index].isrouter = 1; - - /* Look for empty entry. */ - free_router_index = LWIP_ND6_NUM_ROUTERS; - for (router_index = LWIP_ND6_NUM_ROUTERS - 1; router_index >= 0; router_index--) { - /* check if router already exists (this is a special case for 2 netifs on the same subnet - - e.g. wifi and cable) */ - if(default_router_list[router_index].neighbor_entry == &(neighbor_cache[neighbor_index])){ - return router_index; - } - if (default_router_list[router_index].neighbor_entry == NULL) { - /* remember lowest free index to create a new entry */ - free_router_index = router_index; - } - } - if (free_router_index < LWIP_ND6_NUM_ROUTERS) { - default_router_list[free_router_index].neighbor_entry = &(neighbor_cache[neighbor_index]); - return free_router_index; - } - - /* Could not create a router entry. */ - - /* Mark neighbor entry as not-router. Entry might be useful as neighbor still. */ - neighbor_cache[neighbor_index].isrouter = 0; - - /* router not found. */ - return -1; -} - -/** - * Find the cached entry for an on-link prefix. - * - * @param prefix the IPv6 prefix that is on-link - * @param netif the netif on which the prefix is on-link - * @return the index on the prefix table, or -1 if not found - */ -static s8_t -nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif) -{ - s8_t i; - - /* Look for prefix in list. */ - for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { - if ((ip6_addr_netcmp(&(prefix_list[i].prefix), prefix)) && - (prefix_list[i].netif == netif)) { - return i; - } - } - - /* Entry not available. */ - return -1; -} - -/** - * Creates a new entry for an on-link prefix. - * - * @param prefix the IPv6 prefix that is on-link - * @param netif the netif on which the prefix is on-link - * @return the index on the prefix table, or -1 if not created - */ -static s8_t -nd6_new_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif) -{ - s8_t i; - - /* Create new entry. */ - for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { - if ((prefix_list[i].netif == NULL) || - (prefix_list[i].invalidation_timer == 0)) { - /* Found empty prefix entry. */ - prefix_list[i].netif = netif; - ip6_addr_set(&(prefix_list[i].prefix), prefix); - return i; - } - } - - /* Entry not available. */ - return -1; -} - -/** - * Determine the next hop for a destination. Will determine if the - * destination is on-link, else a suitable on-link router is selected. - * - * The last entry index is cached for fast entry search. - * - * @param ip6addr the destination address - * @param netif the netif on which the packet will be sent - * @return the neighbor cache entry for the next hop, ERR_RTE if no - * suitable next hop was found, ERR_MEM if no cache entry - * could be created - */ -static s8_t -nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif) -{ -#ifdef LWIP_HOOK_ND6_GET_GW - const ip6_addr_t *next_hop_addr; -#endif /* LWIP_HOOK_ND6_GET_GW */ - s8_t i; - s16_t dst_idx; - - IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif); - -#if LWIP_NETIF_HWADDRHINT - if (netif->hints != NULL) { - /* per-pcb cached entry was given */ - netif_addr_idx_t addr_hint = netif->hints->addr_hint; - if (addr_hint < LWIP_ND6_NUM_DESTINATIONS) { - nd6_cached_destination_index = addr_hint; - } - } -#endif /* LWIP_NETIF_HWADDRHINT */ - - /* Look for ip6addr in destination cache. */ - if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { - /* the cached entry index is the right one! */ - /* do nothing. */ - ND6_STATS_INC(nd6.cachehit); - } else { - /* Search destination cache. */ - dst_idx = nd6_find_destination_cache_entry(ip6addr); - if (dst_idx >= 0) { - /* found destination entry. make it our new cached index. */ - LWIP_ASSERT("type overflow", (size_t)dst_idx < NETIF_ADDR_IDX_MAX); - nd6_cached_destination_index = (netif_addr_idx_t)dst_idx; - } else { - /* Not found. Create a new destination entry. */ - dst_idx = nd6_new_destination_cache_entry(); - if (dst_idx >= 0) { - /* got new destination entry. make it our new cached index. */ - LWIP_ASSERT("type overflow", (size_t)dst_idx < NETIF_ADDR_IDX_MAX); - nd6_cached_destination_index = (netif_addr_idx_t)dst_idx; - } else { - /* Could not create a destination cache entry. */ - return ERR_MEM; - } - - /* Copy dest address to destination cache. */ - ip6_addr_set(&(destination_cache[nd6_cached_destination_index].destination_addr), ip6addr); - - /* Now find the next hop. is it a neighbor? */ - if (ip6_addr_islinklocal(ip6addr) || - nd6_is_prefix_in_netif(ip6addr, netif)) { - /* Destination in local link. */ - destination_cache[nd6_cached_destination_index].pmtu = netif_mtu6(netif); - ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr); -#ifdef LWIP_HOOK_ND6_GET_GW - } else if ((next_hop_addr = LWIP_HOOK_ND6_GET_GW(netif, ip6addr)) != NULL) { - /* Next hop for destination provided by hook function. */ - destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; - ip6_addr_set(&destination_cache[nd6_cached_destination_index].next_hop_addr, next_hop_addr); -#endif /* LWIP_HOOK_ND6_GET_GW */ - } else { - /* We need to select a router. */ - i = nd6_select_router(ip6addr, netif); - if (i < 0) { - /* No router found. */ - ip6_addr_set_any(&(destination_cache[nd6_cached_destination_index].destination_addr)); - return ERR_RTE; - } - destination_cache[nd6_cached_destination_index].pmtu = netif_mtu6(netif); /* Start with netif mtu, correct through ICMPv6 if necessary */ - ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address); - } - } - } - -#if LWIP_NETIF_HWADDRHINT - if (netif->hints != NULL) { - /* per-pcb cached entry was given */ - netif->hints->addr_hint = nd6_cached_destination_index; - } -#endif /* LWIP_NETIF_HWADDRHINT */ - - /* Look in neighbor cache for the next-hop address. */ - if (ip6_addr_cmp(&(destination_cache[nd6_cached_destination_index].next_hop_addr), - &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { - /* Cache hit. */ - /* Do nothing. */ - ND6_STATS_INC(nd6.cachehit); - } else { - i = nd6_find_neighbor_cache_entry(&(destination_cache[nd6_cached_destination_index].next_hop_addr)); - if (i >= 0) { - /* Found a matching record, make it new cached entry. */ - nd6_cached_neighbor_index = i; - } else { - /* Neighbor not in cache. Make a new entry. */ - i = nd6_new_neighbor_cache_entry(); - if (i >= 0) { - /* got new neighbor entry. make it our new cached index. */ - nd6_cached_neighbor_index = i; - } else { - /* Could not create a neighbor cache entry. */ - return ERR_MEM; - } - - /* Initialize fields. */ - ip6_addr_copy(neighbor_cache[i].next_hop_address, - destination_cache[nd6_cached_destination_index].next_hop_addr); - neighbor_cache[i].isrouter = 0; - neighbor_cache[i].netif = netif; - neighbor_cache[i].state = ND6_INCOMPLETE; - neighbor_cache[i].counter.probes_sent = 1; - nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST); - } - } - - /* Reset this destination's age. */ - destination_cache[nd6_cached_destination_index].age = 0; - - return nd6_cached_neighbor_index; -} - -/** - * Queue a packet for a neighbor. - * - * @param neighbor_index the index in the neighbor cache table - * @param q packet to be queued - * @return ERR_OK if succeeded, ERR_MEM if out of memory - */ -static err_t -nd6_queue_packet(s8_t neighbor_index, struct pbuf *q) -{ - err_t result = ERR_MEM; - struct pbuf *p; - int copy_needed = 0; -#if LWIP_ND6_QUEUEING - struct nd6_q_entry *new_entry, *r; -#endif /* LWIP_ND6_QUEUEING */ - - if ((neighbor_index < 0) || (neighbor_index >= LWIP_ND6_NUM_NEIGHBORS)) { - return ERR_ARG; - } - - /* IF q includes a pbuf that must be copied, we have to copy the whole chain - * into a new PBUF_RAM. See the definition of PBUF_NEEDS_COPY for details. */ - p = q; - while (p) { - if (PBUF_NEEDS_COPY(p)) { - copy_needed = 1; - break; - } - p = p->next; - } - if (copy_needed) { - /* copy the whole packet into new pbufs */ - p = pbuf_clone(PBUF_LINK, PBUF_RAM, q); - while ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { - /* Free oldest packet (as per RFC recommendation) */ -#if LWIP_ND6_QUEUEING - r = neighbor_cache[neighbor_index].q; - neighbor_cache[neighbor_index].q = r->next; - r->next = NULL; - nd6_free_q(r); -#else /* LWIP_ND6_QUEUEING */ - pbuf_free(neighbor_cache[neighbor_index].q); - neighbor_cache[neighbor_index].q = NULL; -#endif /* LWIP_ND6_QUEUEING */ - p = pbuf_clone(PBUF_LINK, PBUF_RAM, q); - } - } else { - /* referencing the old pbuf is enough */ - p = q; - pbuf_ref(p); - } - /* packet was copied/ref'd? */ - if (p != NULL) { - /* queue packet ... */ -#if LWIP_ND6_QUEUEING - /* allocate a new nd6 queue entry */ - new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); - if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { - /* Free oldest packet (as per RFC recommendation) */ - r = neighbor_cache[neighbor_index].q; - neighbor_cache[neighbor_index].q = r->next; - r->next = NULL; - nd6_free_q(r); - new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); - } - if (new_entry != NULL) { - new_entry->next = NULL; - new_entry->p = p; - if (neighbor_cache[neighbor_index].q != NULL) { - /* queue was already existent, append the new entry to the end */ - r = neighbor_cache[neighbor_index].q; - while (r->next != NULL) { - r = r->next; - } - r->next = new_entry; - } else { - /* queue did not exist, first item in queue */ - neighbor_cache[neighbor_index].q = new_entry; - } - LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); - result = ERR_OK; - } else { - /* the pool MEMP_ND6_QUEUE is empty */ - pbuf_free(p); - LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)p)); - /* { result == ERR_MEM } through initialization */ - } -#else /* LWIP_ND6_QUEUEING */ - /* Queue a single packet. If an older packet is already queued, free it as per RFC. */ - if (neighbor_cache[neighbor_index].q != NULL) { - pbuf_free(neighbor_cache[neighbor_index].q); - } - neighbor_cache[neighbor_index].q = p; - LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); - result = ERR_OK; -#endif /* LWIP_ND6_QUEUEING */ - } else { - LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q)); - /* { result == ERR_MEM } through initialization */ - } - - return result; -} - -#if LWIP_ND6_QUEUEING -/** - * Free a complete queue of nd6 q entries - * - * @param q a queue of nd6_q_entry to free - */ -static void -nd6_free_q(struct nd6_q_entry *q) -{ - struct nd6_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_ND6_QUEUE, r); - } -} -#endif /* LWIP_ND6_QUEUEING */ - -/** - * Send queued packets for a neighbor - * - * @param i the neighbor to send packets to - */ -static void -nd6_send_q(s8_t i) -{ - struct ip6_hdr *ip6hdr; - ip6_addr_t dest; -#if LWIP_ND6_QUEUEING - struct nd6_q_entry *q; -#endif /* LWIP_ND6_QUEUEING */ - - if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { - return; - } - -#if LWIP_ND6_QUEUEING - while (neighbor_cache[i].q != NULL) { - /* remember first in queue */ - q = neighbor_cache[i].q; - /* pop first item off the queue */ - neighbor_cache[i].q = q->next; - /* Get ipv6 header. */ - ip6hdr = (struct ip6_hdr *)(q->p->payload); - /* Create an aligned copy. */ - ip6_addr_copy_from_packed(dest, ip6hdr->dest); - /* Restore the zone, if applicable. */ - ip6_addr_assign_zone(&dest, IP6_UNKNOWN, neighbor_cache[i].netif); - /* send the queued IPv6 packet */ - (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, &dest); - /* free the queued IP packet */ - pbuf_free(q->p); - /* now queue entry can be freed */ - memp_free(MEMP_ND6_QUEUE, q); - } -#else /* LWIP_ND6_QUEUEING */ - if (neighbor_cache[i].q != NULL) { - /* Get ipv6 header. */ - ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload); - /* Create an aligned copy. */ - ip6_addr_copy_from_packed(dest, ip6hdr->dest); - /* Restore the zone, if applicable. */ - ip6_addr_assign_zone(&dest, IP6_UNKNOWN, neighbor_cache[i].netif); - /* send the queued IPv6 packet */ - (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, &dest); - /* free the queued IP packet */ - pbuf_free(neighbor_cache[i].q); - neighbor_cache[i].q = NULL; - } -#endif /* LWIP_ND6_QUEUEING */ -} - -/** - * A packet is to be transmitted to a specific IPv6 destination on a specific - * interface. Check if we can find the hardware address of the next hop to use - * for the packet. If so, give the hardware address to the caller, which should - * use it to send the packet right away. Otherwise, enqueue the packet for - * later transmission while looking up the hardware address, if possible. - * - * As such, this function returns one of three different possible results: - * - * - ERR_OK with a non-NULL 'hwaddrp': the caller should send the packet now. - * - ERR_OK with a NULL 'hwaddrp': the packet has been enqueued for later. - * - not ERR_OK: something went wrong; forward the error upward in the stack. - * - * @param netif The lwIP network interface on which the IP packet will be sent. - * @param q The pbuf(s) containing the IP packet to be sent. - * @param ip6addr The destination IPv6 address of the packet. - * @param hwaddrp On success, filled with a pointer to a HW address or NULL (meaning - * the packet has been queued). - * @return - * - ERR_OK on success, ERR_RTE if no route was found for the packet, - * or ERR_MEM if low memory conditions prohibit sending the packet at all. - */ -err_t -nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp) -{ - s8_t i; - - /* Get next hop record. */ - i = nd6_get_next_hop_entry(ip6addr, netif); - if (i < 0) { - /* failed to get a next hop neighbor record. */ - return i; - } - - /* Now that we have a destination record, send or queue the packet. */ - if (neighbor_cache[i].state == ND6_STALE) { - /* Switch to delay state. */ - neighbor_cache[i].state = ND6_DELAY; - neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; - } - /* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */ - if ((neighbor_cache[i].state == ND6_REACHABLE) || - (neighbor_cache[i].state == ND6_DELAY) || - (neighbor_cache[i].state == ND6_PROBE)) { - - /* Tell the caller to send out the packet now. */ - *hwaddrp = neighbor_cache[i].lladdr; - return ERR_OK; - } - - /* We should queue packet on this interface. */ - *hwaddrp = NULL; - return nd6_queue_packet(i, q); -} - - -/** - * Get the Path MTU for a destination. - * - * @param ip6addr the destination address - * @param netif the netif on which the packet will be sent - * @return the Path MTU, if known, or the netif default MTU - */ -u16_t -nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif) -{ - s16_t i; - - i = nd6_find_destination_cache_entry(ip6addr); - if (i >= 0) { - if (destination_cache[i].pmtu > 0) { - return destination_cache[i].pmtu; - } - } - - if (netif != NULL) { - return netif_mtu6(netif); - } - - return 1280; /* Minimum MTU */ -} - - -#if LWIP_ND6_TCP_REACHABILITY_HINTS -/** - * Provide the Neighbor discovery process with a hint that a - * destination is reachable. Called by tcp_receive when ACKs are - * received or sent (as per RFC). This is useful to avoid sending - * NS messages every 30 seconds. - * - * @param ip6addr the destination address which is know to be reachable - * by an upper layer protocol (TCP) - */ -void -nd6_reachability_hint(const ip6_addr_t *ip6addr) -{ - s8_t i; - s16_t dst_idx; - - /* Find destination in cache. */ - if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { - dst_idx = nd6_cached_destination_index; - ND6_STATS_INC(nd6.cachehit); - } else { - dst_idx = nd6_find_destination_cache_entry(ip6addr); - } - if (dst_idx < 0) { - return; - } - - /* Find next hop neighbor in cache. */ - if (ip6_addr_cmp(&(destination_cache[dst_idx].next_hop_addr), &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { - i = nd6_cached_neighbor_index; - ND6_STATS_INC(nd6.cachehit); - } else { - i = nd6_find_neighbor_cache_entry(&(destination_cache[dst_idx].next_hop_addr)); - } - if (i < 0) { - return; - } - - /* For safety: don't set as reachable if we don't have a LL address yet. Misuse protection. */ - if (neighbor_cache[i].state == ND6_INCOMPLETE || neighbor_cache[i].state == ND6_NO_ENTRY) { - return; - } - - /* Set reachability state. */ - neighbor_cache[i].state = ND6_REACHABLE; - neighbor_cache[i].counter.reachable_time = reachable_time; -} -#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ - -/** - * Remove all prefix, neighbor_cache and router entries of the specified netif. - * - * @param netif points to a network interface - */ -void -nd6_cleanup_netif(struct netif *netif) -{ - u8_t i; - s8_t router_index; - for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { - if (prefix_list[i].netif == netif) { - prefix_list[i].netif = NULL; - } - } - for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { - if (neighbor_cache[i].netif == netif) { - for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) { - if (default_router_list[router_index].neighbor_entry == &neighbor_cache[i]) { - default_router_list[router_index].neighbor_entry = NULL; - default_router_list[router_index].flags = 0; - } - } - neighbor_cache[i].isrouter = 0; - nd6_free_neighbor_cache_entry(i); - } - } - /* Clear the destination cache, since many entries may now have become - * invalid for one of several reasons. As destination cache entries have no - * netif association, use a sledgehammer approach (this can be improved). */ - nd6_clear_destination_cache(); -} - -#if LWIP_IPV6_MLD -/** - * The state of a local IPv6 address entry is about to change. If needed, join - * or leave the solicited-node multicast group for the address. - * - * @param netif The netif that owns the address. - * @param addr_idx The index of the address. - * @param new_state The new (IP6_ADDR_) state for the address. - */ -void -nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state) -{ - u8_t old_state, old_member, new_member; - - old_state = netif_ip6_addr_state(netif, addr_idx); - - /* Determine whether we were, and should be, a member of the solicited-node - * multicast group for this address. For tentative addresses, the group is - * not joined until the address enters the TENTATIVE_1 (or VALID) state. */ - old_member = (old_state != IP6_ADDR_INVALID && old_state != IP6_ADDR_DUPLICATED && old_state != IP6_ADDR_TENTATIVE); - new_member = (new_state != IP6_ADDR_INVALID && new_state != IP6_ADDR_DUPLICATED && new_state != IP6_ADDR_TENTATIVE); - - if (old_member != new_member) { - ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, addr_idx)->addr[3]); - ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); - - if (new_member) { - mld6_joingroup_netif(netif, &multicast_address); - } else { - mld6_leavegroup_netif(netif, &multicast_address); - } - } -} -#endif /* LWIP_IPV6_MLD */ - -/** Netif was added, set up, or reconnected (link up) */ -void -nd6_restart_netif(struct netif *netif) -{ -#if LWIP_IPV6_SEND_ROUTER_SOLICIT - /* Send Router Solicitation messages (see RFC 4861, ch. 6.3.7). */ - netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; -#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ -} - -#endif /* LWIP_IPV6 */ diff --git a/core/c/core/mem.c b/core/c/core/mem.c deleted file mode 100755 index 16fd984..0000000 --- a/core/c/core/mem.c +++ /dev/null @@ -1,1017 +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 - * MEMP_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" -#include "lwip/mem.h" -#include "lwip/def.h" -#include "lwip/sys.h" -#include "lwip/stats.h" -#include "lwip/err.h" - -#include - -#if MEM_LIBC_MALLOC -#include /* for malloc()/free() */ -#endif - -/* This is overridable for tests only... */ -#ifndef LWIP_MEM_ILLEGAL_FREE -#define LWIP_MEM_ILLEGAL_FREE(msg) LWIP_ASSERT(msg, 0) -#endif - -#define MEM_STATS_INC_LOCKED(x) SYS_ARCH_LOCKED(MEM_STATS_INC(x)) -#define MEM_STATS_INC_USED_LOCKED(x, y) SYS_ARCH_LOCKED(MEM_STATS_INC_USED(x, y)) -#define MEM_STATS_DEC_USED_LOCKED(x, y) SYS_ARCH_LOCKED(MEM_STATS_DEC_USED(x, y)) - -#if MEM_OVERFLOW_CHECK -#define MEM_SANITY_OFFSET MEM_SANITY_REGION_BEFORE_ALIGNED -#define MEM_SANITY_OVERHEAD (MEM_SANITY_REGION_BEFORE_ALIGNED + MEM_SANITY_REGION_AFTER_ALIGNED) -#else -#define MEM_SANITY_OFFSET 0 -#define MEM_SANITY_OVERHEAD 0 -#endif - -#if MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK -/** - * Check if a mep element was victim of an overflow or underflow - * (e.g. the restricted area after/before it has been altered) - * - * @param p the mem element to check - * @param size allocated size of the element - * @param descr1 description of the element source shown on error - * @param descr2 description of the element source shown on error - */ -void -mem_overflow_check_raw(void *p, size_t size, const char *descr1, const char *descr2) -{ -#if MEM_SANITY_REGION_AFTER_ALIGNED || MEM_SANITY_REGION_BEFORE_ALIGNED - u16_t k; - u8_t *m; - -#if MEM_SANITY_REGION_AFTER_ALIGNED > 0 - m = (u8_t *)p + size; - for (k = 0; k < MEM_SANITY_REGION_AFTER_ALIGNED; k++) { - if (m[k] != 0xcd) { - char errstr[128]; - snprintf(errstr, sizeof(errstr), "detected mem overflow in %s%s", descr1, descr2); - LWIP_ASSERT(errstr, 0); - } - } -#endif /* MEM_SANITY_REGION_AFTER_ALIGNED > 0 */ - -#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0 - m = (u8_t *)p - MEM_SANITY_REGION_BEFORE_ALIGNED; - for (k = 0; k < MEM_SANITY_REGION_BEFORE_ALIGNED; k++) { - if (m[k] != 0xcd) { - char errstr[128]; - snprintf(errstr, sizeof(errstr), "detected mem underflow in %s%s", descr1, descr2); - LWIP_ASSERT(errstr, 0); - } - } -#endif /* MEM_SANITY_REGION_BEFORE_ALIGNED > 0 */ -#else - LWIP_UNUSED_ARG(p); - LWIP_UNUSED_ARG(desc); - LWIP_UNUSED_ARG(descr); -#endif -} - -/** - * Initialize the restricted area of a mem element. - */ -void -mem_overflow_init_raw(void *p, size_t size) -{ -#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0 - u8_t *m; -#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0 - m = (u8_t *)p - MEM_SANITY_REGION_BEFORE_ALIGNED; - memset(m, 0xcd, MEM_SANITY_REGION_BEFORE_ALIGNED); -#endif -#if MEM_SANITY_REGION_AFTER_ALIGNED > 0 - m = (u8_t *)p + size; - memset(m, 0xcd, MEM_SANITY_REGION_AFTER_ALIGNED); -#endif -#else /* MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0 */ - LWIP_UNUSED_ARG(p); - LWIP_UNUSED_ARG(desc); -#endif /* MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0 */ -} -#endif /* MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK */ - -#if MEM_LIBC_MALLOC || MEM_USE_POOLS - -/** mem_init is not used when using pools instead of a heap or using - * C library malloc(). - */ -void -mem_init(void) -{ -} - -/** mem_trim is not used when using pools instead of a heap or using - * C library malloc(): we can't free part of a pool element and the stack - * support mem_trim() to return a different pointer - */ -void * -mem_trim(void *mem, mem_size_t size) -{ - LWIP_UNUSED_ARG(size); - return mem; -} -#endif /* MEM_LIBC_MALLOC || MEM_USE_POOLS */ - -#if MEM_LIBC_MALLOC -/* lwIP heap implemented using C library malloc() */ - -/* in case C library malloc() needs extra protection, - * allow these defines to be overridden. - */ -#ifndef mem_clib_free -#define mem_clib_free free -#endif -#ifndef mem_clib_malloc -#define mem_clib_malloc malloc -#endif -#ifndef mem_clib_calloc -#define mem_clib_calloc calloc -#endif - -#if LWIP_STATS && MEM_STATS -#define MEM_LIBC_STATSHELPER_SIZE LWIP_MEM_ALIGN_SIZE(sizeof(mem_size_t)) -#else -#define MEM_LIBC_STATSHELPER_SIZE 0 -#endif - -/** - * Allocate a block of memory with a minimum of 'size' bytes. - * - * @param size is the minimum size of the requested block in bytes. - * @return pointer to allocated memory or NULL if no free memory was found. - * - * Note that the returned value must always be aligned (as defined by MEM_ALIGNMENT). - */ -void * -mem_malloc(mem_size_t size) -{ - void *ret = mem_clib_malloc(size + MEM_LIBC_STATSHELPER_SIZE); - if (ret == NULL) { - MEM_STATS_INC_LOCKED(err); - } else { - LWIP_ASSERT("malloc() must return aligned memory", LWIP_MEM_ALIGN(ret) == ret); -#if LWIP_STATS && MEM_STATS - *(mem_size_t *)ret = size; - ret = (u8_t *)ret + MEM_LIBC_STATSHELPER_SIZE; - MEM_STATS_INC_USED_LOCKED(used, size); -#endif - } - return ret; -} - -/** Put memory back on the heap - * - * @param rmem is the pointer as returned by a previous call to mem_malloc() - */ -void -mem_free(void *rmem) -{ - LWIP_ASSERT("rmem != NULL", (rmem != NULL)); - LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); -#if LWIP_STATS && MEM_STATS - rmem = (u8_t *)rmem - MEM_LIBC_STATSHELPER_SIZE; - MEM_STATS_DEC_USED_LOCKED(used, *(mem_size_t *)rmem); -#endif - mem_clib_free(rmem); -} - -#elif MEM_USE_POOLS - -/* lwIP heap 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) -{ - void *ret; - struct memp_malloc_helper *element = NULL; - memp_t poolnr; - mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); - - for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) { - /* is this pool big enough to hold an element of the required size - plus a struct memp_malloc_helper that saves the pool this element came from? */ - if (required_size <= memp_pools[poolnr]->size) { - element = (struct memp_malloc_helper *)memp_malloc(poolnr); - if (element == NULL) { - /* No need to DEBUGF or ASSERT: This error is already taken care of in memp.c */ -#if MEM_USE_POOLS_TRY_BIGGER_POOL - /** Try a bigger pool if this one is empty! */ - if (poolnr < MEMP_POOL_LAST) { - continue; - } -#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ - MEM_STATS_INC_LOCKED(err); - return NULL; - } - break; - } - } - if (poolnr > MEMP_POOL_LAST) { - LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); - MEM_STATS_INC_LOCKED(err); - 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 */ - ret = (u8_t *)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); - -#if MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) - /* truncating to u16_t is safe because struct memp_desc::size is u16_t */ - element->size = (u16_t)size; - MEM_STATS_INC_USED_LOCKED(used, element->size); -#endif /* MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) */ -#if MEMP_OVERFLOW_CHECK - /* initialize unused memory (diff between requested size and selected pool's size) */ - memset((u8_t *)ret + size, 0xcd, memp_pools[poolnr]->size - size); -#endif /* MEMP_OVERFLOW_CHECK */ - return ret; -} - -/** - * 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; - - LWIP_ASSERT("rmem != NULL", (rmem != NULL)); - LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); - - /* get the original struct memp_malloc_helper */ - /* cast through void* to get rid of alignment warnings */ - hmem = (struct memp_malloc_helper *)(void *)((u8_t *)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))); - - LWIP_ASSERT("hmem != NULL", (hmem != NULL)); - LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); - LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); - - MEM_STATS_DEC_USED_LOCKED(used, hmem->size); -#if MEMP_OVERFLOW_CHECK - { - u16_t i; - LWIP_ASSERT("MEM_USE_POOLS: invalid chunk size", - hmem->size <= memp_pools[hmem->poolnr]->size); - /* check that unused memory remained untouched (diff between requested size and selected pool's size) */ - for (i = hmem->size; i < memp_pools[hmem->poolnr]->size; i++) { - u8_t data = *((u8_t *)rmem + i); - LWIP_ASSERT("MEM_USE_POOLS: mem overflow detected", data == 0xcd); - } - } -#endif /* MEMP_OVERFLOW_CHECK */ - - /* and put it in the pool we saved earlier */ - memp_free(hmem->poolnr, hmem); -} - -#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 aligns. - */ -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; -#if MEM_OVERFLOW_CHECK - /** this keeps track of the user allocation size for guard checks */ - mem_size_t user_size; -#endif -}; - -/** 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 */ -LWIP_DECLARE_MEMORY_ALIGNED(ram_heap, MEM_SIZE_ALIGNED + (2U * SIZEOF_STRUCT_MEM)); -#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; - -/** concurrent access protection */ -#if !NO_SYS -static sys_mutex_t mem_mutex; -#endif - -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - -static volatile u8_t mem_free_count; - -/* Allow mem_free from other (e.g. interrupt) context */ -#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free) -#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free) -#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free) -#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) -#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc) -#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc) -#define LWIP_MEM_LFREE_VOLATILE volatile - -#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - -/* Protect the heap only by using a mutex */ -#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 mutex AND LWIP_MEM_ALLOC_PROTECT */ -#define LWIP_MEM_ALLOC_DECL_PROTECT() -#define LWIP_MEM_ALLOC_PROTECT() -#define LWIP_MEM_ALLOC_UNPROTECT() -#define LWIP_MEM_LFREE_VOLATILE - -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - -/** pointer to the lowest free block, this is used for faster search */ -static struct mem * LWIP_MEM_LFREE_VOLATILE lfree; - -#if MEM_SANITY_CHECK -static void mem_sanity(void); -#define MEM_SANITY() mem_sanity() -#else -#define MEM_SANITY() -#endif - -#if MEM_OVERFLOW_CHECK -static void -mem_overflow_init_element(struct mem *mem, mem_size_t user_size) -{ - void *p = (u8_t *)mem + SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET; - mem->user_size = user_size; - mem_overflow_init_raw(p, user_size); -} - -static void -mem_overflow_check_element(struct mem *mem) -{ - void *p = (u8_t *)mem + SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET; - mem_overflow_check_raw(p, mem->user_size, "heap", ""); -} -#else /* MEM_OVERFLOW_CHECK */ -#define mem_overflow_init_element(mem, size) -#define mem_overflow_check_element(mem) -#endif /* MEM_OVERFLOW_CHECK */ - -static struct mem * -ptr_to_mem(mem_size_t ptr) -{ - return (struct mem *)(void *)&ram[ptr]; -} - -static mem_size_t -mem_to_ptr(void *mem) -{ - return (mem_size_t)((u8_t *)mem - ram); -} - -/** - * "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 -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 = ptr_to_mem(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; - if (nmem->next != MEM_SIZE_ALIGNED) { - ptr_to_mem(nmem->next)->prev = mem_to_ptr(mem); - } - } - - /* plug hole backward */ - pmem = ptr_to_mem(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; - if (mem->next != MEM_SIZE_ALIGNED) { - ptr_to_mem(mem->next)->prev = mem_to_ptr(pmem); - } - } -} - -/** - * 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 = ptr_to_mem(MEM_SIZE_ALIGNED); - ram_end->used = 1; - ram_end->next = MEM_SIZE_ALIGNED; - ram_end->prev = MEM_SIZE_ALIGNED; - MEM_SANITY(); - - /* 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); - } -} - -/* Check if a struct mem is correctly linked. - * If not, double-free is a possible reason. - */ -static int -mem_link_valid(struct mem *mem) -{ - struct mem *nmem, *pmem; - mem_size_t rmem_idx; - rmem_idx = mem_to_ptr(mem); - nmem = ptr_to_mem(mem->next); - pmem = ptr_to_mem(mem->prev); - if ((mem->next > MEM_SIZE_ALIGNED) || (mem->prev > MEM_SIZE_ALIGNED) || - ((mem->prev != rmem_idx) && (pmem->next != rmem_idx)) || - ((nmem != ram_end) && (nmem->prev != rmem_idx))) { - return 0; - } - return 1; -} - -#if MEM_SANITY_CHECK -static void -mem_sanity(void) -{ - struct mem *mem; - u8_t last_used; - - /* begin with first element here */ - mem = (struct mem *)ram; - LWIP_ASSERT("heap element used valid", (mem->used == 0) || (mem->used == 1)); - last_used = mem->used; - LWIP_ASSERT("heap element prev ptr valid", mem->prev == 0); - LWIP_ASSERT("heap element next ptr valid", mem->next <= MEM_SIZE_ALIGNED); - LWIP_ASSERT("heap element next ptr aligned", LWIP_MEM_ALIGN(ptr_to_mem(mem->next) == ptr_to_mem(mem->next))); - - /* check all elements before the end of the heap */ - for (mem = ptr_to_mem(mem->next); - ((u8_t *)mem > ram) && (mem < ram_end); - mem = ptr_to_mem(mem->next)) { - LWIP_ASSERT("heap element aligned", LWIP_MEM_ALIGN(mem) == mem); - LWIP_ASSERT("heap element prev ptr valid", mem->prev <= MEM_SIZE_ALIGNED); - LWIP_ASSERT("heap element next ptr valid", mem->next <= MEM_SIZE_ALIGNED); - LWIP_ASSERT("heap element prev ptr aligned", LWIP_MEM_ALIGN(ptr_to_mem(mem->prev) == ptr_to_mem(mem->prev))); - LWIP_ASSERT("heap element next ptr aligned", LWIP_MEM_ALIGN(ptr_to_mem(mem->next) == ptr_to_mem(mem->next))); - - if (last_used == 0) { - /* 2 unused elements in a row? */ - LWIP_ASSERT("heap element unused?", mem->used == 1); - } else { - LWIP_ASSERT("heap element unused member", (mem->used == 0) || (mem->used == 1)); - } - - LWIP_ASSERT("heap element link valid", mem_link_valid(mem)); - - /* used/unused altering */ - last_used = mem->used; - } - LWIP_ASSERT("heap end ptr sanity", mem == ptr_to_mem(MEM_SIZE_ALIGNED)); - LWIP_ASSERT("heap element used valid", mem->used == 1); - LWIP_ASSERT("heap element prev ptr valid", mem->prev == MEM_SIZE_ALIGNED); - LWIP_ASSERT("heap element next ptr valid", mem->next == MEM_SIZE_ALIGNED); -} -#endif /* MEM_SANITY_CHECK */ - -/** - * 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; - } - if ((((mem_ptr_t)rmem) & (MEM_ALIGNMENT - 1)) != 0) { - LWIP_MEM_ILLEGAL_FREE("mem_free: sanity check alignment"); - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: sanity check alignment\n")); - /* protect mem stats from concurrent access */ - MEM_STATS_INC_LOCKED(illegal); - return; - } - - /* Get the corresponding struct mem: */ - /* cast through void* to get rid of alignment warnings */ - mem = (struct mem *)(void *)((u8_t *)rmem - (SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET)); - - if ((u8_t *)mem < ram || (u8_t *)rmem + MIN_SIZE_ALIGNED > (u8_t *)ram_end) { - LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory"); - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n")); - /* protect mem stats from concurrent access */ - MEM_STATS_INC_LOCKED(illegal); - return; - } -#if MEM_OVERFLOW_CHECK - mem_overflow_check_element(mem); -#endif - /* protect the heap from concurrent access */ - LWIP_MEM_FREE_PROTECT(); - /* mem has to be in a used state */ - if (!mem->used) { - LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory: double free"); - LWIP_MEM_FREE_UNPROTECT(); - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory: double free?\n")); - /* protect mem stats from concurrent access */ - MEM_STATS_INC_LOCKED(illegal); - return; - } - - if (!mem_link_valid(mem)) { - LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory: non-linked: double free"); - LWIP_MEM_FREE_UNPROTECT(); - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory: non-linked: double free?\n")); - /* protect mem stats from concurrent access */ - MEM_STATS_INC_LOCKED(illegal); - return; - } - - /* mem 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); - MEM_SANITY(); -#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 new_size 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 new_size) -{ - mem_size_t size, newsize; - 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 = (mem_size_t)LWIP_MEM_ALIGN_SIZE(new_size); - if (newsize < MIN_SIZE_ALIGNED) { - /* every data block must be at least MIN_SIZE_ALIGNED long */ - newsize = MIN_SIZE_ALIGNED; - } -#if MEM_OVERFLOW_CHECK - newsize += MEM_SANITY_REGION_BEFORE_ALIGNED + MEM_SANITY_REGION_AFTER_ALIGNED; -#endif - if ((newsize > MEM_SIZE_ALIGNED) || (newsize < new_size)) { - 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) { - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n")); - /* protect mem stats from concurrent access */ - MEM_STATS_INC_LOCKED(illegal); - return rmem; - } - /* Get the corresponding struct mem ... */ - /* cast through void* to get rid of alignment warnings */ - mem = (struct mem *)(void *)((u8_t *)rmem - (SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET)); -#if MEM_OVERFLOW_CHECK - mem_overflow_check_element(mem); -#endif - /* ... and its offset pointer */ - ptr = mem_to_ptr(mem); - - size = (mem_size_t)((mem_size_t)(mem->next - ptr) - (SIZEOF_STRUCT_MEM + MEM_SANITY_OVERHEAD)); - 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 = ptr_to_mem(mem->next); - if (mem2->used == 0) { - /* The next struct is unused, we can simply move it at little */ - mem_size_t next; - LWIP_ASSERT("invalid next ptr", mem->next != MEM_SIZE_ALIGNED); - /* remember the old next pointer */ - next = mem2->next; - /* create new struct mem which is moved directly after the shrinked mem */ - ptr2 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + newsize); - if (lfree == mem2) { - lfree = ptr_to_mem(ptr2); - } - mem2 = ptr_to_mem(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) { - ptr_to_mem(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 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + newsize); - LWIP_ASSERT("invalid next ptr", mem->next != MEM_SIZE_ALIGNED); - mem2 = ptr_to_mem(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) { - ptr_to_mem(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 MEM_OVERFLOW_CHECK - mem_overflow_init_element(mem, new_size); -#endif - MEM_SANITY(); -#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; -} - -/** - * Allocate a block of memory with a minimum of 'size' bytes. - * - * @param size_in 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_in) -{ - mem_size_t ptr, ptr2, size; - 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_in == 0) { - return NULL; - } - - /* Expand the size of the allocated memory region so that we can - adjust for alignment. */ - size = (mem_size_t)LWIP_MEM_ALIGN_SIZE(size_in); - if (size < MIN_SIZE_ALIGNED) { - /* every data block must be at least MIN_SIZE_ALIGNED long */ - size = MIN_SIZE_ALIGNED; - } -#if MEM_OVERFLOW_CHECK - size += MEM_SANITY_REGION_BEFORE_ALIGNED + MEM_SANITY_REGION_AFTER_ALIGNED; -#endif - if ((size > MEM_SIZE_ALIGNED) || (size < size_in)) { - 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 or mem_trim */ - 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_to_ptr(lfree); ptr < MEM_SIZE_ALIGNED - size; - ptr = ptr_to_mem(ptr)->next) { - mem = ptr_to_mem(ptr); -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - mem_free_count = 0; - LWIP_MEM_ALLOC_UNPROTECT(); - /* allow mem_free or mem_trim to run */ - LWIP_MEM_ALLOC_PROTECT(); - if (mem_free_count != 0) { - /* If mem_free or mem_trim have run, we have to restart since they - could have altered our current struct mem. */ - local_mem_free_count = 1; - break; - } -#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 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + size); - LWIP_ASSERT("invalid next ptr",ptr2 != MEM_SIZE_ALIGNED); - /* create mem2 struct */ - mem2 = ptr_to_mem(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) { - ptr_to_mem(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 exact 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_to_ptr(mem)); - } -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT -mem_malloc_adjust_lfree: -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - if (mem == lfree) { - struct mem *cur = lfree; - /* Find next free block after mem and update lowest free pointer */ - while (cur->used && cur != ram_end) { -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - mem_free_count = 0; - LWIP_MEM_ALLOC_UNPROTECT(); - /* prevent high interrupt latency... */ - LWIP_MEM_ALLOC_PROTECT(); - if (mem_free_count != 0) { - /* If mem_free or mem_trim have run, we have to restart since they - could have altered our current struct mem or lfree. */ - goto mem_malloc_adjust_lfree; - } -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - cur = ptr_to_mem(cur->next); - } - lfree = cur; - 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); - -#if MEM_OVERFLOW_CHECK - mem_overflow_init_element(mem, size_in); -#endif - MEM_SANITY(); - return (u8_t *)mem + SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET; - } - } -#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 */ - MEM_STATS_INC(err); - LWIP_MEM_ALLOC_UNPROTECT(); - sys_mutex_unlock(&mem_mutex); - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); - return NULL; -} - -#endif /* MEM_USE_POOLS */ - -#if MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) -void * -mem_calloc(mem_size_t count, mem_size_t size) -{ - return mem_clib_calloc(count, size); -} - -#else /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */ -/** - * Contiguously allocates enough space for count objects that are size bytes - * of memory each and returns a pointer to the allocated memory. - * - * 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; - size_t alloc_size = (size_t)count * (size_t)size; - - if ((size_t)(mem_size_t)alloc_size != alloc_size) { - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_calloc: could not allocate %"SZT_F" bytes\n", alloc_size)); - return NULL; - } - - /* allocate 'count' objects of size 'size' */ - p = mem_malloc((mem_size_t)alloc_size); - if (p) { - /* zero the memory */ - memset(p, 0, alloc_size); - } - return p; -} -#endif /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */ diff --git a/core/c/core/memp.c b/core/c/core/memp.c deleted file mode 100755 index 18771f6..0000000 --- a/core/c/core/memp.c +++ /dev/null @@ -1,447 +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. - * - * @defgroup mempool Memory pools - * @ingroup infrastructure - * Custom memory pools - - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * 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/sys.h" -#include "lwip/stats.h" - -#include - -/* Make sure we include everything we need for size calculation required by memp_std.h */ -#include "lwip/pbuf.h" -#include "lwip/raw.h" -#include "lwip/udp.h" -#include "lwip/tcp.h" -#include "lwip/priv/tcp_priv.h" -#include "lwip/altcp.h" -#include "lwip/ip4_frag.h" -#include "lwip/netbuf.h" -#include "lwip/api.h" -#include "lwip/priv/tcpip_priv.h" -#include "lwip/priv/api_msg.h" -#include "lwip/priv/sockets_priv.h" -#include "lwip/etharp.h" -#include "lwip/igmp.h" -#include "lwip/timeouts.h" -/* needed by default MEMP_NUM_SYS_TIMEOUT */ -#include "netif/ppp/ppp_opts.h" -#include "lwip/netdb.h" -#include "lwip/dns.h" -#include "lwip/priv/nd6_priv.h" -#include "lwip/ip6_frag.h" -#include "lwip/mld6.h" - -#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc) -#include "lwip/priv/memp_std.h" - -const struct memp_desc *const memp_pools[MEMP_MAX] = { -#define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name, -#include "lwip/priv/memp_std.h" -}; - -#ifdef LWIP_HOOK_FILENAME -#include LWIP_HOOK_FILENAME -#endif - -#if MEMP_MEM_MALLOC && MEMP_OVERFLOW_CHECK >= 2 -#undef MEMP_OVERFLOW_CHECK -/* MEMP_OVERFLOW_CHECK >= 2 does not work with MEMP_MEM_MALLOC, use 1 instead */ -#define MEMP_OVERFLOW_CHECK 1 -#endif - -#if MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC -/** - * Check that memp-lists don't form a circle, using "Floyd's cycle-finding algorithm". - */ -static int -memp_sanity(const struct memp_desc *desc) -{ - struct memp *t, *h; - - t = *desc->tab; - if (t != NULL) { - for (h = t->next; (t != NULL) && (h != NULL); t = t->next, - h = ((h->next != NULL) ? h->next->next : NULL)) { - if (t == h) { - return 0; - } - } - } - - return 1; -} -#endif /* MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC */ - -#if MEMP_OVERFLOW_CHECK -/** - * Check if a memp element was victim of an overflow or underflow - * (e.g. the restricted area after/before it has been altered) - * - * @param p the memp element to check - * @param desc the pool p comes from - */ -static void -memp_overflow_check_element(struct memp *p, const struct memp_desc *desc) -{ - mem_overflow_check_raw((u8_t *)p + MEMP_SIZE, desc->size, "pool ", desc->desc); -} - -/** - * Initialize the restricted area of on memp element. - */ -static void -memp_overflow_init_element(struct memp *p, const struct memp_desc *desc) -{ - mem_overflow_init_raw((u8_t *)p + MEMP_SIZE, desc->size); -} - -#if MEMP_OVERFLOW_CHECK >= 2 -/** - * Do an overflow check for all elements in every pool. - * - * @see memp_overflow_check_element for a description of the check - */ -static void -memp_overflow_check_all(void) -{ - u16_t i, j; - struct memp *p; - SYS_ARCH_DECL_PROTECT(old_level); - SYS_ARCH_PROTECT(old_level); - - for (i = 0; i < MEMP_MAX; ++i) { - p = (struct memp *)LWIP_MEM_ALIGN(memp_pools[i]->base); - for (j = 0; j < memp_pools[i]->num; ++j) { - memp_overflow_check_element(p, memp_pools[i]); - p = LWIP_ALIGNMENT_CAST(struct memp *, ((u8_t *)p + MEMP_SIZE + memp_pools[i]->size + MEM_SANITY_REGION_AFTER_ALIGNED)); - } - } - SYS_ARCH_UNPROTECT(old_level); -} -#endif /* MEMP_OVERFLOW_CHECK >= 2 */ -#endif /* MEMP_OVERFLOW_CHECK */ - -/** - * Initialize custom memory pool. - * Related functions: memp_malloc_pool, memp_free_pool - * - * @param desc pool to initialize - */ -void -memp_init_pool(const struct memp_desc *desc) -{ -#if MEMP_MEM_MALLOC - LWIP_UNUSED_ARG(desc); -#else - int i; - struct memp *memp; - - *desc->tab = NULL; - memp = (struct memp *)LWIP_MEM_ALIGN(desc->base); -#if MEMP_MEM_INIT - /* force memset on pool memory */ - memset(memp, 0, (size_t)desc->num * (MEMP_SIZE + desc->size -#if MEMP_OVERFLOW_CHECK - + MEM_SANITY_REGION_AFTER_ALIGNED -#endif - )); -#endif - /* create a linked list of memp elements */ - for (i = 0; i < desc->num; ++i) { - memp->next = *desc->tab; - *desc->tab = memp; -#if MEMP_OVERFLOW_CHECK - memp_overflow_init_element(memp, desc); -#endif /* MEMP_OVERFLOW_CHECK */ - /* cast through void* to get rid of alignment warnings */ - memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size -#if MEMP_OVERFLOW_CHECK - + MEM_SANITY_REGION_AFTER_ALIGNED -#endif - ); - } -#if MEMP_STATS - desc->stats->avail = desc->num; -#endif /* MEMP_STATS */ -#endif /* !MEMP_MEM_MALLOC */ - -#if MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) - desc->stats->name = desc->desc; -#endif /* MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) */ -} - -/** - * Initializes lwIP built-in pools. - * Related functions: memp_malloc, memp_free - * - * Carves out memp_memory into linked lists for each pool-type. - */ -void -memp_init(void) -{ - u16_t i; - - /* for every pool: */ - for (i = 0; i < LWIP_ARRAYSIZE(memp_pools); i++) { - memp_init_pool(memp_pools[i]); - -#if LWIP_STATS && MEMP_STATS - lwip_stats.memp[i] = memp_pools[i]->stats; -#endif - } - -#if MEMP_OVERFLOW_CHECK >= 2 - /* check everything a first time to see if it worked */ - memp_overflow_check_all(); -#endif /* MEMP_OVERFLOW_CHECK >= 2 */ -} - -static void * -#if !MEMP_OVERFLOW_CHECK -do_memp_malloc_pool(const struct memp_desc *desc) -#else -do_memp_malloc_pool_fn(const struct memp_desc *desc, const char *file, const int line) -#endif -{ - struct memp *memp; - SYS_ARCH_DECL_PROTECT(old_level); - -#if MEMP_MEM_MALLOC - memp = (struct memp *)mem_malloc(MEMP_SIZE + MEMP_ALIGN_SIZE(desc->size)); - SYS_ARCH_PROTECT(old_level); -#else /* MEMP_MEM_MALLOC */ - SYS_ARCH_PROTECT(old_level); - - memp = *desc->tab; -#endif /* MEMP_MEM_MALLOC */ - - if (memp != NULL) { -#if !MEMP_MEM_MALLOC -#if MEMP_OVERFLOW_CHECK == 1 - memp_overflow_check_element(memp, desc); -#endif /* MEMP_OVERFLOW_CHECK */ - - *desc->tab = memp->next; -#if MEMP_OVERFLOW_CHECK - memp->next = NULL; -#endif /* MEMP_OVERFLOW_CHECK */ -#endif /* !MEMP_MEM_MALLOC */ -#if MEMP_OVERFLOW_CHECK - memp->file = file; - memp->line = line; -#if MEMP_MEM_MALLOC - memp_overflow_init_element(memp, desc); -#endif /* MEMP_MEM_MALLOC */ -#endif /* MEMP_OVERFLOW_CHECK */ - LWIP_ASSERT("memp_malloc: memp properly aligned", - ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0); -#if MEMP_STATS - desc->stats->used++; - if (desc->stats->used > desc->stats->max) { - desc->stats->max = desc->stats->used; - } -#endif - SYS_ARCH_UNPROTECT(old_level); - /* cast through u8_t* to get rid of alignment warnings */ - return ((u8_t *)memp + MEMP_SIZE); - } else { -#if MEMP_STATS - desc->stats->err++; -#endif - SYS_ARCH_UNPROTECT(old_level); - LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", desc->desc)); - } - - return NULL; -} - -/** - * Get an element from a custom pool. - * - * @param desc the pool to get an element from - * - * @return a pointer to the allocated memory or a NULL pointer on error - */ -void * -#if !MEMP_OVERFLOW_CHECK -memp_malloc_pool(const struct memp_desc *desc) -#else -memp_malloc_pool_fn(const struct memp_desc *desc, const char *file, const int line) -#endif -{ - LWIP_ASSERT("invalid pool desc", desc != NULL); - if (desc == NULL) { - return NULL; - } - -#if !MEMP_OVERFLOW_CHECK - return do_memp_malloc_pool(desc); -#else - return do_memp_malloc_pool_fn(desc, file, line); -#endif -} - -/** - * Get an element from a specific pool. - * - * @param type the pool to get an element from - * - * @return a pointer to the allocated memory or a NULL pointer on error - */ -void * -#if !MEMP_OVERFLOW_CHECK -memp_malloc(memp_t type) -#else -memp_malloc_fn(memp_t type, const char *file, const int line) -#endif -{ - void *memp; - LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;); - -#if MEMP_OVERFLOW_CHECK >= 2 - memp_overflow_check_all(); -#endif /* MEMP_OVERFLOW_CHECK >= 2 */ - -#if !MEMP_OVERFLOW_CHECK - memp = do_memp_malloc_pool(memp_pools[type]); -#else - memp = do_memp_malloc_pool_fn(memp_pools[type], file, line); -#endif - - return memp; -} - -static void -do_memp_free_pool(const struct memp_desc *desc, void *mem) -{ - struct memp *memp; - SYS_ARCH_DECL_PROTECT(old_level); - - LWIP_ASSERT("memp_free: mem properly aligned", - ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0); - - /* cast through void* to get rid of alignment warnings */ - memp = (struct memp *)(void *)((u8_t *)mem - MEMP_SIZE); - - SYS_ARCH_PROTECT(old_level); - -#if MEMP_OVERFLOW_CHECK == 1 - memp_overflow_check_element(memp, desc); -#endif /* MEMP_OVERFLOW_CHECK */ - -#if MEMP_STATS - desc->stats->used--; -#endif - -#if MEMP_MEM_MALLOC - LWIP_UNUSED_ARG(desc); - SYS_ARCH_UNPROTECT(old_level); - mem_free(memp); -#else /* MEMP_MEM_MALLOC */ - memp->next = *desc->tab; - *desc->tab = memp; - -#if MEMP_SANITY_CHECK - LWIP_ASSERT("memp sanity", memp_sanity(desc)); -#endif /* MEMP_SANITY_CHECK */ - - SYS_ARCH_UNPROTECT(old_level); -#endif /* !MEMP_MEM_MALLOC */ -} - -/** - * Put a custom pool element back into its pool. - * - * @param desc the pool where to put mem - * @param mem the memp element to free - */ -void -memp_free_pool(const struct memp_desc *desc, void *mem) -{ - LWIP_ASSERT("invalid pool desc", desc != NULL); - if ((desc == NULL) || (mem == NULL)) { - return; - } - - do_memp_free_pool(desc, mem); -} - -/** - * 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) -{ -#ifdef LWIP_HOOK_MEMP_AVAILABLE - struct memp *old_first; -#endif - - LWIP_ERROR("memp_free: type < MEMP_MAX", (type < MEMP_MAX), return;); - - if (mem == NULL) { - return; - } - -#if MEMP_OVERFLOW_CHECK >= 2 - memp_overflow_check_all(); -#endif /* MEMP_OVERFLOW_CHECK >= 2 */ - -#ifdef LWIP_HOOK_MEMP_AVAILABLE - old_first = *memp_pools[type]->tab; -#endif - - do_memp_free_pool(memp_pools[type], mem); - -#ifdef LWIP_HOOK_MEMP_AVAILABLE - if (old_first == NULL) { - LWIP_HOOK_MEMP_AVAILABLE(type); - } -#endif -} diff --git a/core/c/core/netif.c b/core/c/core/netif.c deleted file mode 100755 index a19018c..0000000 --- a/core/c/core/netif.c +++ /dev/null @@ -1,1795 +0,0 @@ -/** - * @file - * lwIP network interface abstraction - * - * @defgroup netif Network interface (NETIF) - * @ingroup callbackstyle_api - * - * @defgroup netif_ip4 IPv4 address handling - * @ingroup netif - * - * @defgroup netif_ip6 IPv6 address handling - * @ingroup netif - * - * @defgroup netif_cd Client data handling - * Store data (void*) on a netif for application usage. - * @see @ref LWIP_NUM_NETIF_CLIENT_DATA - * @ingroup netif - */ - -/* - * 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 /* memset */ -#include /* atoi */ - -#include "lwip/def.h" -#include "lwip/ip_addr.h" -#include "lwip/ip6_addr.h" -#include "lwip/netif.h" -#include "lwip/priv/tcp_priv.h" -#include "lwip/udp.h" -#include "lwip/priv/raw_priv.h" -#include "lwip/snmp.h" -#include "lwip/igmp.h" -#include "lwip/etharp.h" -#include "lwip/stats.h" -#include "lwip/sys.h" -#include "lwip/ip.h" -#if ENABLE_LOOPBACK -#if LWIP_NETIF_LOOPBACK_MULTITHREADING -#include "lwip/tcpip.h" -#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ -#endif /* ENABLE_LOOPBACK */ - -#include "netif/ethernet.h" - -#if LWIP_AUTOIP -#include "lwip/autoip.h" -#endif /* LWIP_AUTOIP */ -#if LWIP_DHCP -#include "lwip/dhcp.h" -#endif /* LWIP_DHCP */ -#if LWIP_IPV6_DHCP6 -#include "lwip/dhcp6.h" -#endif /* LWIP_IPV6_DHCP6 */ -#if LWIP_IPV6_MLD -#include "lwip/mld6.h" -#endif /* LWIP_IPV6_MLD */ -#if LWIP_IPV6 -#include "lwip/nd6.h" -#endif - -#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 */ - -#if LWIP_NETIF_EXT_STATUS_CALLBACK -static netif_ext_callback_t *ext_callback; -#endif - -#if !LWIP_SINGLE_NETIF -struct netif *netif_list; -#endif /* !LWIP_SINGLE_NETIF */ -struct netif *netif_default; - -#define netif_index_to_num(index) ((index) - 1) -static u8_t netif_num; - -#if LWIP_NUM_NETIF_CLIENT_DATA > 0 -static u8_t netif_client_id; -#endif - -#define NETIF_REPORT_TYPE_IPV4 0x01 -#define NETIF_REPORT_TYPE_IPV6 0x02 -static void netif_issue_reports(struct netif *netif, u8_t report_type); - -#if LWIP_IPV6 -static err_t netif_null_output_ip6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr); -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 -static err_t netif_null_output_ip4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr); -#endif /* LWIP_IPV4 */ - -#if LWIP_HAVE_LOOPIF -#if LWIP_IPV4 -static err_t netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr); -#endif -#if LWIP_IPV6 -static err_t netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr); -#endif - - -static struct netif loop_netif; - -/** - * Initialize a lwip network interface structure for a loopback interface - * - * @param netif the lwip network interface structure for this loopif - * @return ERR_OK if the loopif is initialized - * ERR_MEM if private data couldn't be allocated - */ -static err_t -netif_loopif_init(struct netif *netif) -{ - LWIP_ASSERT("netif_loopif_init: invalid netif", netif != NULL); - - /* initialize the snmp variables and counters inside the struct netif - * ifSpeed: no assumption can be made! - */ - MIB2_INIT_NETIF(netif, snmp_ifType_softwareLoopback, 0); - - netif->name[0] = 'l'; - netif->name[1] = 'o'; -#if LWIP_IPV4 - netif->output = netif_loop_output_ipv4; -#endif -#if LWIP_IPV6 - netif->output_ip6 = netif_loop_output_ipv6; -#endif -#if LWIP_LOOPIF_MULTICAST - netif_set_flags(netif, NETIF_FLAG_IGMP); -#endif - NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_DISABLE_ALL); - return ERR_OK; -} -#endif /* LWIP_HAVE_LOOPIF */ - -void -netif_init(void) -{ -#if LWIP_HAVE_LOOPIF -#if LWIP_IPV4 -#define LOOPIF_ADDRINIT &loop_ipaddr, &loop_netmask, &loop_gw, - ip4_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); -#else /* LWIP_IPV4 */ -#define LOOPIF_ADDRINIT -#endif /* LWIP_IPV4 */ - -#if NO_SYS - netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, ip_input); -#else /* NO_SYS */ - netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, tcpip_input); -#endif /* NO_SYS */ - -#if LWIP_IPV6 - IP_ADDR6_HOST(loop_netif.ip6_addr, 0, 0, 0, 0x00000001UL); - loop_netif.ip6_addr_state[0] = IP6_ADDR_VALID; -#endif /* LWIP_IPV6 */ - - netif_set_link_up(&loop_netif); - netif_set_up(&loop_netif); - -#endif /* LWIP_HAVE_LOOPIF */ -} - -/** - * @ingroup lwip_nosys - * Forwards a received packet for input processing with - * ethernet_input() or ip_input() depending on netif flags. - * Don't call directly, pass to netif_add() and call - * netif->input(). - * Only works if the netif driver correctly sets - * NETIF_FLAG_ETHARP and/or NETIF_FLAG_ETHERNET flag! - */ -err_t -netif_input(struct pbuf *p, struct netif *inp) -{ - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ASSERT("netif_input: invalid pbuf", p != NULL); - LWIP_ASSERT("netif_input: invalid netif", inp != NULL); - -#if LWIP_ETHERNET - if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { - return ethernet_input(p, inp); - } else -#endif /* LWIP_ETHERNET */ - return ip_input(p, inp); -} - -/** - * @ingroup netif - * Add a network interface to the list of lwIP netifs. - * - * Same as @ref netif_add but without IPv4 addresses - */ -struct netif * -netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input) -{ - return netif_add(netif, -#if LWIP_IPV4 - NULL, NULL, NULL, -#endif /* LWIP_IPV4*/ - state, init, input); -} - -/** - * @ingroup netif - * 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.\n - * It is recommended to use a function that passes the input directly - * to the stack (netif_input(), NO_SYS=1 mode) or via sending a - * message to TCPIP thread (tcpip_input(), NO_SYS=0 mode).\n - * These functions use netif flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET - * to decide whether to forward to ethernet_input() or ip_input(). - * In other words, the functions only work when the netif - * driver is implemented correctly!\n - * Most members of struct netif should be be initialized by the - * netif init function = netif driver (init parameter of this function).\n - * IPv6: Don't forget to call netif_create_ip6_linklocal_address() after - * setting the MAC address in struct netif.hwaddr - * (IPv6 requires a link-local address). - * - * @return netif, or NULL if failed. - */ -struct netif * -netif_add(struct netif *netif, -#if LWIP_IPV4 - const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, -#endif /* LWIP_IPV4 */ - void *state, netif_init_fn init, netif_input_fn input) -{ -#if LWIP_IPV6 - s8_t i; -#endif - - LWIP_ASSERT_CORE_LOCKED(); - -#if LWIP_SINGLE_NETIF - if (netif_default != NULL) { - LWIP_ASSERT("single netif already set", 0); - return NULL; - } -#endif - - LWIP_ERROR("netif_add: invalid netif", netif != NULL, return NULL); - LWIP_ERROR("netif_add: No init function given", init != NULL, return NULL); - -#if LWIP_IPV4 - if (ipaddr == NULL) { - ipaddr = ip_2_ip4(IP4_ADDR_ANY); - } - if (netmask == NULL) { - netmask = ip_2_ip4(IP4_ADDR_ANY); - } - if (gw == NULL) { - gw = ip_2_ip4(IP4_ADDR_ANY); - } - - /* reset new interface configuration state */ - ip_addr_set_zero_ip4(&netif->ip_addr); - ip_addr_set_zero_ip4(&netif->netmask); - ip_addr_set_zero_ip4(&netif->gw); - netif->output = netif_null_output_ip4; -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - ip_addr_set_zero_ip6(&netif->ip6_addr[i]); - netif->ip6_addr_state[i] = IP6_ADDR_INVALID; -#if LWIP_IPV6_ADDRESS_LIFETIMES - netif->ip6_addr_valid_life[i] = IP6_ADDR_LIFE_STATIC; - netif->ip6_addr_pref_life[i] = IP6_ADDR_LIFE_STATIC; -#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ - } - netif->output_ip6 = netif_null_output_ip6; -#endif /* LWIP_IPV6 */ - NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL); - netif->mtu = 0; - netif->flags = 0; -#ifdef netif_get_client_data - memset(netif->client_data, 0, sizeof(netif->client_data)); -#endif /* LWIP_NUM_NETIF_CLIENT_DATA */ -#if LWIP_IPV6 -#if LWIP_IPV6_AUTOCONFIG - /* IPv6 address autoconfiguration not enabled by default */ - netif->ip6_autoconfig_enabled = 0; -#endif /* LWIP_IPV6_AUTOCONFIG */ - nd6_restart_netif(netif); -#endif /* LWIP_IPV6 */ -#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 LWIP_IPV6 && LWIP_IPV6_MLD - netif->mld_mac_filter = NULL; -#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ -#if ENABLE_LOOPBACK - netif->loop_first = NULL; - netif->loop_last = NULL; -#endif /* ENABLE_LOOPBACK */ - - /* remember netif specific state information data */ - netif->state = state; - netif->num = netif_num; - netif->input = input; - - NETIF_RESET_HINTS(netif); -#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS - netif->loop_cnt_current = 0; -#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ - -#if LWIP_IPV4 - netif_set_addr(netif, ipaddr, netmask, gw); -#endif /* LWIP_IPV4 */ - - /* call user specified initialization function for netif */ - if (init(netif) != ERR_OK) { - return NULL; - } -#if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES - /* Initialize the MTU for IPv6 to the one set by the netif driver. - This can be updated later by RA. */ - netif->mtu6 = netif->mtu; -#endif /* LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES */ - -#if !LWIP_SINGLE_NETIF - /* Assign a unique netif number in the range [0..254], so that (num+1) can - serve as an interface index that fits in a u8_t. - We assume that the new netif has not yet been added to the list here. - This algorithm is O(n^2), but that should be OK for lwIP. - */ - { - struct netif *netif2; - int num_netifs; - do { - if (netif->num == 255) { - netif->num = 0; - } - num_netifs = 0; - for (netif2 = netif_list; netif2 != NULL; netif2 = netif2->next) { - LWIP_ASSERT("netif already added", netif2 != netif); - num_netifs++; - LWIP_ASSERT("too many netifs, max. supported number is 255", num_netifs <= 255); - if (netif2->num == netif->num) { - netif->num++; - break; - } - } - } while (netif2 != NULL); - } - if (netif->num == 254) { - netif_num = 0; - } else { - netif_num = (u8_t)(netif->num + 1); - } - - /* add this netif to the list */ - netif->next = netif_list; - netif_list = netif; -#endif /* "LWIP_SINGLE_NETIF */ - mib2_netif_added(netif); - -#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", - netif->name[0], netif->name[1])); -#if LWIP_IPV4 - LWIP_DEBUGF(NETIF_DEBUG, (" addr ")); - ip4_addr_debug_print(NETIF_DEBUG, ipaddr); - LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); - ip4_addr_debug_print(NETIF_DEBUG, netmask); - LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); - ip4_addr_debug_print(NETIF_DEBUG, gw); -#endif /* LWIP_IPV4 */ - LWIP_DEBUGF(NETIF_DEBUG, ("\n")); - - netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_ADDED, NULL); - - return netif; -} - -static void -netif_do_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) -{ -#if LWIP_TCP - tcp_netif_ip_addr_changed(old_addr, new_addr); -#endif /* LWIP_TCP */ -#if LWIP_UDP - udp_netif_ip_addr_changed(old_addr, new_addr); -#endif /* LWIP_UDP */ -#if LWIP_RAW - raw_netif_ip_addr_changed(old_addr, new_addr); -#endif /* LWIP_RAW */ -} - -#if LWIP_IPV4 -static int -netif_do_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr, ip_addr_t *old_addr) -{ - LWIP_ASSERT("invalid pointer", ipaddr != NULL); - LWIP_ASSERT("invalid pointer", old_addr != NULL); - - /* address is actually being changed? */ - if (ip4_addr_cmp(ipaddr, netif_ip4_addr(netif)) == 0) { - ip_addr_t new_addr; - *ip_2_ip4(&new_addr) = *ipaddr; - IP_SET_TYPE_VAL(new_addr, IPADDR_TYPE_V4); - - ip_addr_copy(*old_addr, *netif_ip_addr4(netif)); - - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); - netif_do_ip_addr_changed(old_addr, &new_addr); - - mib2_remove_ip4(netif); - mib2_remove_route_ip4(0, netif); - /* set new IP address to netif */ - ip4_addr_set(ip_2_ip4(&netif->ip_addr), ipaddr); - IP_SET_TYPE_VAL(netif->ip_addr, IPADDR_TYPE_V4); - mib2_add_ip4(netif); - mib2_add_route_ip4(0, netif); - - netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4); - - NETIF_STATUS_CALLBACK(netif); - return 1; /* address changed */ - } - return 0; /* address unchanged */ -} - -/** - * @ingroup netif_ip4 - * 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, const ip4_addr_t *ipaddr) -{ - ip_addr_t old_addr; - - LWIP_ERROR("netif_set_ipaddr: invalid netif", netif != NULL, return); - - /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ - if (ipaddr == NULL) { - ipaddr = IP4_ADDR_ANY4; - } - - LWIP_ASSERT_CORE_LOCKED(); - - if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) { -#if LWIP_NETIF_EXT_STATUS_CALLBACK - netif_ext_callback_args_t args; - args.ipv4_changed.old_address = &old_addr; - netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_ADDRESS_CHANGED, &args); -#endif - } -} - -static int -netif_do_set_netmask(struct netif *netif, const ip4_addr_t *netmask, ip_addr_t *old_nm) -{ - /* address is actually being changed? */ - if (ip4_addr_cmp(netmask, netif_ip4_netmask(netif)) == 0) { -#if LWIP_NETIF_EXT_STATUS_CALLBACK - LWIP_ASSERT("invalid pointer", old_nm != NULL); - ip_addr_copy(*old_nm, *netif_ip_netmask4(netif)); -#else - LWIP_UNUSED_ARG(old_nm); -#endif - mib2_remove_route_ip4(0, netif); - /* set new netmask to netif */ - ip4_addr_set(ip_2_ip4(&netif->netmask), netmask); - IP_SET_TYPE_VAL(netif->netmask, IPADDR_TYPE_V4); - mib2_add_route_ip4(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_ip4_netmask(netif)), - ip4_addr2_16(netif_ip4_netmask(netif)), - ip4_addr3_16(netif_ip4_netmask(netif)), - ip4_addr4_16(netif_ip4_netmask(netif)))); - return 1; /* netmask changed */ - } - return 0; /* netmask unchanged */ -} - -/** - * @ingroup netif_ip4 - * 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, const ip4_addr_t *netmask) -{ -#if LWIP_NETIF_EXT_STATUS_CALLBACK - ip_addr_t old_nm_val; - ip_addr_t *old_nm = &old_nm_val; -#else - ip_addr_t *old_nm = NULL; -#endif - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("netif_set_netmask: invalid netif", netif != NULL, return); - - /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ - if (netmask == NULL) { - netmask = IP4_ADDR_ANY4; - } - - if (netif_do_set_netmask(netif, netmask, old_nm)) { -#if LWIP_NETIF_EXT_STATUS_CALLBACK - netif_ext_callback_args_t args; - args.ipv4_changed.old_netmask = old_nm; - netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_NETMASK_CHANGED, &args); -#endif - } -} - -static int -netif_do_set_gw(struct netif *netif, const ip4_addr_t *gw, ip_addr_t *old_gw) -{ - /* address is actually being changed? */ - if (ip4_addr_cmp(gw, netif_ip4_gw(netif)) == 0) { -#if LWIP_NETIF_EXT_STATUS_CALLBACK - LWIP_ASSERT("invalid pointer", old_gw != NULL); - ip_addr_copy(*old_gw, *netif_ip_gw4(netif)); -#else - LWIP_UNUSED_ARG(old_gw); -#endif - - ip4_addr_set(ip_2_ip4(&netif->gw), gw); - IP_SET_TYPE_VAL(netif->gw, IPADDR_TYPE_V4); - 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_ip4_gw(netif)), - ip4_addr2_16(netif_ip4_gw(netif)), - ip4_addr3_16(netif_ip4_gw(netif)), - ip4_addr4_16(netif_ip4_gw(netif)))); - return 1; /* gateway changed */ - } - return 0; /* gateway unchanged */ -} - -/** - * @ingroup netif_ip4 - * 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, const ip4_addr_t *gw) -{ -#if LWIP_NETIF_EXT_STATUS_CALLBACK - ip_addr_t old_gw_val; - ip_addr_t *old_gw = &old_gw_val; -#else - ip_addr_t *old_gw = NULL; -#endif - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("netif_set_gw: invalid netif", netif != NULL, return); - - /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ - if (gw == NULL) { - gw = IP4_ADDR_ANY4; - } - - if (netif_do_set_gw(netif, gw, old_gw)) { -#if LWIP_NETIF_EXT_STATUS_CALLBACK - netif_ext_callback_args_t args; - args.ipv4_changed.old_gw = old_gw; - netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_GATEWAY_CHANGED, &args); -#endif - } -} - -/** - * @ingroup netif_ip4 - * 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, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, - const ip4_addr_t *gw) -{ -#if LWIP_NETIF_EXT_STATUS_CALLBACK - netif_nsc_reason_t change_reason = LWIP_NSC_NONE; - netif_ext_callback_args_t cb_args; - ip_addr_t old_nm_val; - ip_addr_t old_gw_val; - ip_addr_t *old_nm = &old_nm_val; - ip_addr_t *old_gw = &old_gw_val; -#else - ip_addr_t *old_nm = NULL; - ip_addr_t *old_gw = NULL; -#endif - ip_addr_t old_addr; - int remove; - - LWIP_ASSERT_CORE_LOCKED(); - - /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ - if (ipaddr == NULL) { - ipaddr = IP4_ADDR_ANY4; - } - if (netmask == NULL) { - netmask = IP4_ADDR_ANY4; - } - if (gw == NULL) { - gw = IP4_ADDR_ANY4; - } - - remove = ip4_addr_isany(ipaddr); - if (remove) { - /* when removing an address, we have to remove it *before* changing netmask/gw - to ensure that tcp RST segment can be sent correctly */ - if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) { -#if LWIP_NETIF_EXT_STATUS_CALLBACK - change_reason |= LWIP_NSC_IPV4_ADDRESS_CHANGED; - cb_args.ipv4_changed.old_address = &old_addr; -#endif - } - } - if (netif_do_set_netmask(netif, netmask, old_nm)) { -#if LWIP_NETIF_EXT_STATUS_CALLBACK - change_reason |= LWIP_NSC_IPV4_NETMASK_CHANGED; - cb_args.ipv4_changed.old_netmask = old_nm; -#endif - } - if (netif_do_set_gw(netif, gw, old_gw)) { -#if LWIP_NETIF_EXT_STATUS_CALLBACK - change_reason |= LWIP_NSC_IPV4_GATEWAY_CHANGED; - cb_args.ipv4_changed.old_gw = old_gw; -#endif - } - if (!remove) { - /* set ipaddr last to ensure netmask/gw have been set when status callback is called */ - if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) { -#if LWIP_NETIF_EXT_STATUS_CALLBACK - change_reason |= LWIP_NSC_IPV4_ADDRESS_CHANGED; - cb_args.ipv4_changed.old_address = &old_addr; -#endif - } - } - -#if LWIP_NETIF_EXT_STATUS_CALLBACK - if (change_reason != LWIP_NSC_NONE) { - change_reason |= LWIP_NSC_IPV4_SETTINGS_CHANGED; - netif_invoke_ext_callback(netif, change_reason, &cb_args); - } -#endif -} -#endif /* LWIP_IPV4*/ - -/** - * @ingroup netif - * Remove a network interface from the list of lwIP netifs. - * - * @param netif the network interface to remove - */ -void -netif_remove(struct netif *netif) -{ -#if LWIP_IPV6 - int i; -#endif - - LWIP_ASSERT_CORE_LOCKED(); - - if (netif == NULL) { - return; - } - - netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_REMOVED, NULL); - -#if LWIP_IPV4 - if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { - netif_do_ip_addr_changed(netif_ip_addr4(netif), NULL); - } - -#if LWIP_IGMP - /* stop IGMP processing */ - if (netif->flags & NETIF_FLAG_IGMP) { - igmp_stop(netif); - } -#endif /* LWIP_IGMP */ -#endif /* LWIP_IPV4*/ - -#if LWIP_IPV6 - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) { - netif_do_ip_addr_changed(netif_ip_addr6(netif, i), NULL); - } - } -#if LWIP_IPV6_MLD - /* stop MLD processing */ - mld6_stop(netif); -#endif /* LWIP_IPV6_MLD */ -#endif /* LWIP_IPV6 */ - if (netif_is_up(netif)) { - /* set netif down before removing (call callback function) */ - netif_set_down(netif); - } - - mib2_remove_ip4(netif); - - /* this netif is default? */ - if (netif_default == netif) { - /* reset default netif */ - netif_set_default(NULL); - } -#if !LWIP_SINGLE_NETIF - /* is it the first netif? */ - if (netif_list == netif) { - netif_list = netif->next; - } else { - /* look for netif further down the list */ - struct netif *tmp_netif; - NETIF_FOREACH(tmp_netif) { - if (tmp_netif->next == netif) { - tmp_netif->next = netif->next; - break; - } - } - if (tmp_netif == NULL) { - return; /* netif is not on the list */ - } - } -#endif /* !LWIP_SINGLE_NETIF */ - mib2_netif_removed(netif); -#if LWIP_NETIF_REMOVE_CALLBACK - if (netif->remove_callback) { - netif->remove_callback(netif); - } -#endif /* LWIP_NETIF_REMOVE_CALLBACK */ - LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); -} - -/** - * @ingroup netif - * 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) -{ - LWIP_ASSERT_CORE_LOCKED(); - - if (netif == NULL) { - /* remove default route */ - mib2_remove_route_ip4(1, netif); - } else { - /* install default route */ - mib2_add_route_ip4(1, netif); - } - netif_default = netif; - LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", - netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); -} - -/** - * @ingroup netif - * Bring an interface up, available for processing - * traffic. - */ -void -netif_set_up(struct netif *netif) -{ - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("netif_set_up: invalid netif", netif != NULL, return); - - if (!(netif->flags & NETIF_FLAG_UP)) { - netif_set_flags(netif, NETIF_FLAG_UP); - - MIB2_COPY_SYSUPTIME_TO(&netif->ts); - - NETIF_STATUS_CALLBACK(netif); - -#if LWIP_NETIF_EXT_STATUS_CALLBACK - { - netif_ext_callback_args_t args; - args.status_changed.state = 1; - netif_invoke_ext_callback(netif, LWIP_NSC_STATUS_CHANGED, &args); - } -#endif - - netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4 | NETIF_REPORT_TYPE_IPV6); -#if LWIP_IPV6 - nd6_restart_netif(netif); -#endif /* LWIP_IPV6 */ - } -} - -/** Send ARP/IGMP/MLD/RS events, e.g. on link-up/netif-up or addr-change - */ -static void -netif_issue_reports(struct netif *netif, u8_t report_type) -{ - LWIP_ASSERT("netif_issue_reports: invalid netif", netif != NULL); - - /* Only send reports when both link and admin states are up */ - if (!(netif->flags & NETIF_FLAG_LINK_UP) || - !(netif->flags & NETIF_FLAG_UP)) { - return; - } - -#if LWIP_IPV4 - if ((report_type & NETIF_REPORT_TYPE_IPV4) && - !ip4_addr_isany_val(*netif_ip4_addr(netif))) { -#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 */ - } -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6 - if (report_type & NETIF_REPORT_TYPE_IPV6) { -#if LWIP_IPV6_MLD - /* send mld memberships */ - mld6_report_groups(netif); -#endif /* LWIP_IPV6_MLD */ - } -#endif /* LWIP_IPV6 */ -} - -/** - * @ingroup netif - * Bring an interface down, disabling any traffic processing. - */ -void -netif_set_down(struct netif *netif) -{ - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("netif_set_down: invalid netif", netif != NULL, return); - - if (netif->flags & NETIF_FLAG_UP) { -#if LWIP_NETIF_EXT_STATUS_CALLBACK - { - netif_ext_callback_args_t args; - args.status_changed.state = 0; - netif_invoke_ext_callback(netif, LWIP_NSC_STATUS_CHANGED, &args); - } -#endif - - netif_clear_flags(netif, NETIF_FLAG_UP); - MIB2_COPY_SYSUPTIME_TO(&netif->ts); - -#if LWIP_IPV4 && LWIP_ARP - if (netif->flags & NETIF_FLAG_ETHARP) { - etharp_cleanup_netif(netif); - } -#endif /* LWIP_IPV4 && LWIP_ARP */ - -#if LWIP_IPV6 - nd6_cleanup_netif(netif); -#endif /* LWIP_IPV6 */ - - NETIF_STATUS_CALLBACK(netif); - } -} - -#if LWIP_NETIF_STATUS_CALLBACK -/** - * @ingroup netif - * Set callback to be called when interface is brought up/down or address is changed while up - */ -void -netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback) -{ - LWIP_ASSERT_CORE_LOCKED(); - - if (netif) { - netif->status_callback = status_callback; - } -} -#endif /* LWIP_NETIF_STATUS_CALLBACK */ - -#if LWIP_NETIF_REMOVE_CALLBACK -/** - * @ingroup netif - * Set callback to be called when the interface has been removed - */ -void -netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback) -{ - LWIP_ASSERT_CORE_LOCKED(); - - if (netif) { - netif->remove_callback = remove_callback; - } -} -#endif /* LWIP_NETIF_REMOVE_CALLBACK */ - -/** - * @ingroup netif - * Called by a driver when its link goes up - */ -void -netif_set_link_up(struct netif *netif) -{ - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("netif_set_link_up: invalid netif", netif != NULL, return); - - if (!(netif->flags & NETIF_FLAG_LINK_UP)) { - netif_set_flags(netif, NETIF_FLAG_LINK_UP); - -#if LWIP_DHCP - dhcp_network_changed(netif); -#endif /* LWIP_DHCP */ - -#if LWIP_AUTOIP - autoip_network_changed(netif); -#endif /* LWIP_AUTOIP */ - - netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4 | NETIF_REPORT_TYPE_IPV6); -#if LWIP_IPV6 - nd6_restart_netif(netif); -#endif /* LWIP_IPV6 */ - - NETIF_LINK_CALLBACK(netif); -#if LWIP_NETIF_EXT_STATUS_CALLBACK - { - netif_ext_callback_args_t args; - args.link_changed.state = 1; - netif_invoke_ext_callback(netif, LWIP_NSC_LINK_CHANGED, &args); - } -#endif - } -} - -/** - * @ingroup netif - * Called by a driver when its link goes down - */ -void -netif_set_link_down(struct netif *netif) -{ - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("netif_set_link_down: invalid netif", netif != NULL, return); - - if (netif->flags & NETIF_FLAG_LINK_UP) { - netif_clear_flags(netif, NETIF_FLAG_LINK_UP); - NETIF_LINK_CALLBACK(netif); -#if LWIP_NETIF_EXT_STATUS_CALLBACK - { - netif_ext_callback_args_t args; - args.link_changed.state = 0; - netif_invoke_ext_callback(netif, LWIP_NSC_LINK_CHANGED, &args); - } -#endif - } -} - -#if LWIP_NETIF_LINK_CALLBACK -/** - * @ingroup netif - * 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) -{ - LWIP_ASSERT_CORE_LOCKED(); - - if (netif) { - netif->link_callback = link_callback; - } -} -#endif /* LWIP_NETIF_LINK_CALLBACK */ - -#if ENABLE_LOOPBACK -/** - * @ingroup netif - * 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' - * @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) -{ - struct pbuf *r; - err_t err; - struct pbuf *last; -#if LWIP_LOOPBACK_MAX_PBUFS - u16_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 MIB2_STATS -#if LWIP_HAVE_LOOPIF - struct netif *stats_if = &loop_netif; -#else /* LWIP_HAVE_LOOPIF */ - struct netif *stats_if = netif; -#endif /* LWIP_HAVE_LOOPIF */ -#endif /* MIB2_STATS */ -#if LWIP_NETIF_LOOPBACK_MULTITHREADING - u8_t schedule_poll = 0; -#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ - SYS_ARCH_DECL_PROTECT(lev); - - LWIP_ASSERT("netif_loop_output: invalid netif", netif != NULL); - LWIP_ASSERT("netif_loop_output: invalid pbuf", p != NULL); - - /* 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); - MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards); - 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_MIN(LWIP_LOOPBACK_MAX_PBUFS, 0xFFFF))) { - pbuf_free(r); - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards); - return ERR_MEM; - } - netif->loop_cnt_current = (u16_t)(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); - MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards); - 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) { - /* nothing to do here, just get to the last pbuf */ - } - - 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; -#if LWIP_NETIF_LOOPBACK_MULTITHREADING - /* No existing packets queued, schedule poll */ - schedule_poll = 1; -#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ - } - SYS_ARCH_UNPROTECT(lev); - - LINK_STATS_INC(link.xmit); - MIB2_STATS_NETIF_ADD(stats_if, ifoutoctets, p->tot_len); - MIB2_STATS_NETIF_INC(stats_if, ifoutucastpkts); - -#if LWIP_NETIF_LOOPBACK_MULTITHREADING - /* For multithreading environment, schedule a call to netif_poll */ - if (schedule_poll) { - tcpip_try_callback((tcpip_callback_fn)netif_poll, netif); - } -#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ - - return ERR_OK; -} - -#if LWIP_HAVE_LOOPIF -#if LWIP_IPV4 -static err_t -netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr) -{ - LWIP_UNUSED_ARG(addr); - return netif_loop_output(netif, p); -} -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6 -static err_t -netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr) -{ - LWIP_UNUSED_ARG(addr); - return netif_loop_output(netif, p); -} -#endif /* LWIP_IPV6 */ -#endif /* LWIP_HAVE_LOOPIF */ - - -/** - * 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) -{ - /* If we have a loopif, SNMP counters are adjusted for it, - * if not they are adjusted for 'netif'. */ -#if MIB2_STATS -#if LWIP_HAVE_LOOPIF - struct netif *stats_if = &loop_netif; -#else /* LWIP_HAVE_LOOPIF */ - struct netif *stats_if = netif; -#endif /* LWIP_HAVE_LOOPIF */ -#endif /* MIB2_STATS */ - SYS_ARCH_DECL_PROTECT(lev); - - LWIP_ASSERT("netif_poll: invalid netif", netif != NULL); - - /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ - SYS_ARCH_PROTECT(lev); - while (netif->loop_first != NULL) { - struct pbuf *in, *in_end; -#if LWIP_LOOPBACK_MAX_PBUFS - u8_t clen = 1; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - - in = in_end = netif->loop_first; - 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; -#if LWIP_LOOPBACK_MAX_PBUFS - clen++; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - } -#if LWIP_LOOPBACK_MAX_PBUFS - /* 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 = (u16_t)(netif->loop_cnt_current - clen); -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - - /* '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); - - in->if_idx = netif_get_index(netif); - - LINK_STATS_INC(link.recv); - MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len); - MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts); - /* loopback packets are always IP packets! */ - if (ip_input(in, netif) != ERR_OK) { - pbuf_free(in); - } - SYS_ARCH_PROTECT(lev); - } - SYS_ARCH_UNPROTECT(lev); -} - -#if !LWIP_NETIF_LOOPBACK_MULTITHREADING -/** - * Calls netif_poll() for every netif on the netif_list. - */ -void -netif_poll_all(void) -{ - struct netif *netif; - /* loop through netifs */ - NETIF_FOREACH(netif) { - netif_poll(netif); - } -} -#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ -#endif /* ENABLE_LOOPBACK */ - -#if LWIP_NUM_NETIF_CLIENT_DATA > 0 -/** - * @ingroup netif_cd - * Allocate an index to store data in client_data member of struct netif. - * Returned value is an index in mentioned array. - * @see LWIP_NUM_NETIF_CLIENT_DATA - */ -u8_t -netif_alloc_client_data_id(void) -{ - u8_t result = netif_client_id; - netif_client_id++; - - LWIP_ASSERT_CORE_LOCKED(); - -#if LWIP_NUM_NETIF_CLIENT_DATA > 256 -#error LWIP_NUM_NETIF_CLIENT_DATA must be <= 256 -#endif - LWIP_ASSERT("Increase LWIP_NUM_NETIF_CLIENT_DATA in lwipopts.h", result < LWIP_NUM_NETIF_CLIENT_DATA); - return (u8_t)(result + LWIP_NETIF_CLIENT_DATA_INDEX_MAX); -} -#endif - -#if LWIP_IPV6 -/** - * @ingroup netif_ip6 - * Change an IPv6 address of a network interface - * - * @param netif the network interface to change - * @param addr_idx index of the IPv6 address - * @param addr6 the new IPv6 address - * - * @note call netif_ip6_addr_set_state() to set the address valid/temptative - */ -void -netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, const ip6_addr_t *addr6) -{ - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ASSERT("netif_ip6_addr_set: invalid netif", netif != NULL); - LWIP_ASSERT("netif_ip6_addr_set: invalid addr6", addr6 != NULL); - - netif_ip6_addr_set_parts(netif, addr_idx, addr6->addr[0], addr6->addr[1], - addr6->addr[2], addr6->addr[3]); -} - -/* - * Change an IPv6 address of a network interface (internal version taking 4 * u32_t) - * - * @param netif the network interface to change - * @param addr_idx index of the IPv6 address - * @param i0 word0 of the new IPv6 address - * @param i1 word1 of the new IPv6 address - * @param i2 word2 of the new IPv6 address - * @param i3 word3 of the new IPv6 address - */ -void -netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, u32_t i2, u32_t i3) -{ - ip_addr_t old_addr; - ip_addr_t new_ipaddr; - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ASSERT("netif != NULL", netif != NULL); - LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES); - - ip6_addr_copy(*ip_2_ip6(&old_addr), *netif_ip6_addr(netif, addr_idx)); - IP_SET_TYPE_VAL(old_addr, IPADDR_TYPE_V6); - - /* address is actually being changed? */ - if ((ip_2_ip6(&old_addr)->addr[0] != i0) || (ip_2_ip6(&old_addr)->addr[1] != i1) || - (ip_2_ip6(&old_addr)->addr[2] != i2) || (ip_2_ip6(&old_addr)->addr[3] != i3)) { - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set: netif address being changed\n")); - - IP_ADDR6(&new_ipaddr, i0, i1, i2, i3); - ip6_addr_assign_zone(ip_2_ip6(&new_ipaddr), IP6_UNICAST, netif); - - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addr_idx))) { - netif_do_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr); - } - /* @todo: remove/readd mib2 ip6 entries? */ - - ip_addr_copy(netif->ip6_addr[addr_idx], new_ipaddr); - - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addr_idx))) { - netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6); - NETIF_STATUS_CALLBACK(netif); - } - -#if LWIP_NETIF_EXT_STATUS_CALLBACK - { - netif_ext_callback_args_t args; - args.ipv6_set.addr_index = addr_idx; - args.ipv6_set.old_address = &old_addr; - netif_invoke_ext_callback(netif, LWIP_NSC_IPV6_SET, &args); - } -#endif - } - - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IPv6 address %d of interface %c%c set to %s/0x%"X8_F"\n", - addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)), - netif_ip6_addr_state(netif, addr_idx))); -} - -/** - * @ingroup netif_ip6 - * Change the state of an IPv6 address of a network interface - * (INVALID, TEMPTATIVE, PREFERRED, DEPRECATED, where TEMPTATIVE - * includes the number of checks done, see ip6_addr.h) - * - * @param netif the network interface to change - * @param addr_idx index of the IPv6 address - * @param state the new IPv6 address state - */ -void -netif_ip6_addr_set_state(struct netif *netif, s8_t addr_idx, u8_t state) -{ - u8_t old_state; - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ASSERT("netif != NULL", netif != NULL); - LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES); - - old_state = netif_ip6_addr_state(netif, addr_idx); - /* state is actually being changed? */ - if (old_state != state) { - u8_t old_valid = old_state & IP6_ADDR_VALID; - u8_t new_valid = state & IP6_ADDR_VALID; - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set_state: netif address state being changed\n")); - -#if LWIP_IPV6_MLD - /* Reevaluate solicited-node multicast group membership. */ - if (netif->flags & NETIF_FLAG_MLD6) { - nd6_adjust_mld_membership(netif, addr_idx, state); - } -#endif /* LWIP_IPV6_MLD */ - - if (old_valid && !new_valid) { - /* address about to be removed by setting invalid */ - netif_do_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL); - /* @todo: remove mib2 ip6 entries? */ - } - netif->ip6_addr_state[addr_idx] = state; - - if (!old_valid && new_valid) { - /* address added by setting valid */ - /* This is a good moment to check that the address is properly zoned. */ - IP6_ADDR_ZONECHECK_NETIF(netif_ip6_addr(netif, addr_idx), netif); - /* @todo: add mib2 ip6 entries? */ - netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6); - } - if ((old_state & ~IP6_ADDR_TENTATIVE_COUNT_MASK) != - (state & ~IP6_ADDR_TENTATIVE_COUNT_MASK)) { - /* address state has changed -> call the callback function */ - NETIF_STATUS_CALLBACK(netif); - } - -#if LWIP_NETIF_EXT_STATUS_CALLBACK - { - netif_ext_callback_args_t args; - args.ipv6_addr_state_changed.addr_index = addr_idx; - args.ipv6_addr_state_changed.old_state = old_state; - args.ipv6_addr_state_changed.address = netif_ip_addr6(netif, addr_idx); - netif_invoke_ext_callback(netif, LWIP_NSC_IPV6_ADDR_STATE_CHANGED, &args); - } -#endif - } - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IPv6 address %d of interface %c%c set to %s/0x%"X8_F"\n", - addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)), - netif_ip6_addr_state(netif, addr_idx))); -} - -/** - * Checks if a specific local address is present on the netif and returns its - * index. Depending on its state, it may or may not be assigned to the - * interface (as per RFC terminology). - * - * The given address may or may not be zoned (i.e., have a zone index other - * than IP6_NO_ZONE). If the address is zoned, it must have the correct zone - * for the given netif, or no match will be found. - * - * @param netif the netif to check - * @param ip6addr the IPv6 address to find - * @return >= 0: address found, this is its index - * -1: address not found on this netif - */ -s8_t -netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr) -{ - s8_t i; - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ASSERT("netif_get_ip6_addr_match: invalid netif", netif != NULL); - LWIP_ASSERT("netif_get_ip6_addr_match: invalid ip6addr", ip6addr != NULL); - -#if LWIP_IPV6_SCOPES - if (ip6_addr_has_zone(ip6addr) && !ip6_addr_test_zone(ip6addr, netif)) { - return -1; /* wrong zone, no match */ - } -#endif /* LWIP_IPV6_SCOPES */ - - for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_cmp_zoneless(netif_ip6_addr(netif, i), ip6addr)) { - return i; - } - } - return -1; -} - -/** - * @ingroup netif_ip6 - * Create a link-local IPv6 address on a netif (stored in slot 0) - * - * @param netif the netif to create the address on - * @param from_mac_48bit if != 0, assume hwadr is a 48-bit MAC address (std conversion) - * if == 0, use hwaddr directly as interface ID - */ -void -netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit) -{ - u8_t i, addr_index; - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ASSERT("netif_create_ip6_linklocal_address: invalid netif", netif != NULL); - - /* Link-local prefix. */ - ip_2_ip6(&netif->ip6_addr[0])->addr[0] = PP_HTONL(0xfe800000ul); - ip_2_ip6(&netif->ip6_addr[0])->addr[1] = 0; - - /* Generate interface ID. */ - if (from_mac_48bit) { - /* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */ - ip_2_ip6(&netif->ip6_addr[0])->addr[2] = lwip_htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) | - ((u32_t)(netif->hwaddr[1]) << 16) | - ((u32_t)(netif->hwaddr[2]) << 8) | - (0xff)); - ip_2_ip6(&netif->ip6_addr[0])->addr[3] = lwip_htonl((u32_t)(0xfeul << 24) | - ((u32_t)(netif->hwaddr[3]) << 16) | - ((u32_t)(netif->hwaddr[4]) << 8) | - (netif->hwaddr[5])); - } else { - /* Use hwaddr directly as interface ID. */ - ip_2_ip6(&netif->ip6_addr[0])->addr[2] = 0; - ip_2_ip6(&netif->ip6_addr[0])->addr[3] = 0; - - addr_index = 3; - for (i = 0; (i < 8) && (i < netif->hwaddr_len); i++) { - if (i == 4) { - addr_index--; - } - ip_2_ip6(&netif->ip6_addr[0])->addr[addr_index] |= lwip_htonl(((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03))); - } - } - - /* Set a link-local zone. Even though the zone is implied by the owning - * netif, setting the zone anyway has two important conceptual advantages: - * 1) it avoids the need for a ton of exceptions in internal code, allowing - * e.g. ip6_addr_cmp() to be used on local addresses; - * 2) the properly zoned address is visible externally, e.g. when any outside - * code enumerates available addresses or uses one to bind a socket. - * Any external code unaware of address scoping is likely to just ignore the - * zone field, so this should not create any compatibility problems. */ - ip6_addr_assign_zone(ip_2_ip6(&netif->ip6_addr[0]), IP6_UNICAST, netif); - - /* Set address state. */ -#if LWIP_IPV6_DUP_DETECT_ATTEMPTS - /* Will perform duplicate address detection (DAD). */ - netif_ip6_addr_set_state(netif, 0, IP6_ADDR_TENTATIVE); -#else - /* Consider address valid. */ - netif_ip6_addr_set_state(netif, 0, IP6_ADDR_PREFERRED); -#endif /* LWIP_IPV6_AUTOCONFIG */ -} - -/** - * @ingroup netif_ip6 - * This function allows for the easy addition of a new IPv6 address to an interface. - * It takes care of finding an empty slot and then sets the address tentative - * (to make sure that all the subsequent processing happens). - * - * @param netif netif to add the address on - * @param ip6addr address to add - * @param chosen_idx if != NULL, the chosen IPv6 address index will be stored here - */ -err_t -netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx) -{ - s8_t i; - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ASSERT("netif_add_ip6_address: invalid netif", netif != NULL); - LWIP_ASSERT("netif_add_ip6_address: invalid ip6addr", ip6addr != NULL); - - i = netif_get_ip6_addr_match(netif, ip6addr); - if (i >= 0) { - /* Address already added */ - if (chosen_idx != NULL) { - *chosen_idx = i; - } - return ERR_OK; - } - - /* Find a free slot. The first one is reserved for link-local addresses. */ - for (i = ip6_addr_islinklocal(ip6addr) ? 0 : 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) { - ip_addr_copy_from_ip6(netif->ip6_addr[i], *ip6addr); - ip6_addr_assign_zone(ip_2_ip6(&netif->ip6_addr[i]), IP6_UNICAST, netif); - netif_ip6_addr_set_state(netif, i, IP6_ADDR_TENTATIVE); - if (chosen_idx != NULL) { - *chosen_idx = i; - } - return ERR_OK; - } - } - - if (chosen_idx != NULL) { - *chosen_idx = -1; - } - return ERR_VAL; -} - -/** Dummy IPv6 output function for netifs not supporting IPv6 - */ -static err_t -netif_null_output_ip6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) -{ - LWIP_UNUSED_ARG(netif); - LWIP_UNUSED_ARG(p); - LWIP_UNUSED_ARG(ipaddr); - - return ERR_IF; -} -#endif /* LWIP_IPV6 */ - -#if LWIP_IPV4 -/** Dummy IPv4 output function for netifs not supporting IPv4 - */ -static err_t -netif_null_output_ip4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) -{ - LWIP_UNUSED_ARG(netif); - LWIP_UNUSED_ARG(p); - LWIP_UNUSED_ARG(ipaddr); - - return ERR_IF; -} -#endif /* LWIP_IPV4 */ - -/** -* @ingroup netif -* Return the interface index for the netif with name -* or NETIF_NO_INDEX if not found/on error -* -* @param name the name of the netif -*/ -u8_t -netif_name_to_index(const char *name) -{ - struct netif *netif = netif_find(name); - if (netif != NULL) { - return netif_get_index(netif); - } - /* No name found, return invalid index */ - return NETIF_NO_INDEX; -} - -/** -* @ingroup netif -* Return the interface name for the netif matching index -* or NULL if not found/on error -* -* @param idx the interface index of the netif -* @param name char buffer of at least NETIF_NAMESIZE bytes -*/ -char * -netif_index_to_name(u8_t idx, char *name) -{ - struct netif *netif = netif_get_by_index(idx); - - if (netif != NULL) { - name[0] = netif->name[0]; - name[1] = netif->name[1]; - lwip_itoa(&name[2], NETIF_NAMESIZE - 2, netif_index_to_num(idx)); - return name; - } - return NULL; -} - -/** -* @ingroup netif -* Return the interface for the netif index -* -* @param idx index of netif to find -*/ -struct netif * -netif_get_by_index(u8_t idx) -{ - struct netif *netif; - - LWIP_ASSERT_CORE_LOCKED(); - - if (idx != NETIF_NO_INDEX) { - NETIF_FOREACH(netif) { - if (idx == netif_get_index(netif)) { - return netif; /* found! */ - } - } - } - - return NULL; -} - -/** - * @ingroup netif - * 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(const char *name) -{ - struct netif *netif; - u8_t num; - - LWIP_ASSERT_CORE_LOCKED(); - - if (name == NULL) { - return NULL; - } - - num = (u8_t)atoi(&name[2]); - - NETIF_FOREACH(netif) { - 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; -} - -#if LWIP_NETIF_EXT_STATUS_CALLBACK -/** - * @ingroup netif - * Add extended netif events listener - * @param callback pointer to listener structure - * @param fn callback function - */ -void -netif_add_ext_callback(netif_ext_callback_t *callback, netif_ext_callback_fn fn) -{ - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ASSERT("callback must be != NULL", callback != NULL); - LWIP_ASSERT("fn must be != NULL", fn != NULL); - - callback->callback_fn = fn; - callback->next = ext_callback; - ext_callback = callback; -} - -/** - * @ingroup netif - * Remove extended netif events listener - * @param callback pointer to listener structure - */ -void -netif_remove_ext_callback(netif_ext_callback_t* callback) -{ - netif_ext_callback_t *last, *iter; - - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ASSERT("callback must be != NULL", callback != NULL); - - if (ext_callback == NULL) { - return; - } - - if (callback == ext_callback) { - ext_callback = ext_callback->next; - } else { - last = ext_callback; - for (iter = ext_callback->next; iter != NULL; last = iter, iter = iter->next) { - if (iter == callback) { - LWIP_ASSERT("last != NULL", last != NULL); - last->next = callback->next; - callback->next = NULL; - return; - } - } - } -} - -/** - * Invoke extended netif status event - * @param netif netif that is affected by change - * @param reason change reason - * @param args depends on reason, see reason description - */ -void -netif_invoke_ext_callback(struct netif *netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t *args) -{ - netif_ext_callback_t *callback = ext_callback; - - LWIP_ASSERT("netif must be != NULL", netif != NULL); - - while (callback != NULL) { - callback->callback_fn(netif, reason, args); - callback = callback->next; - } -} -#endif /* LWIP_NETIF_EXT_STATUS_CALLBACK */ diff --git a/core/c/core/pbuf.c b/core/c/core/pbuf.c deleted file mode 100755 index 7579d86..0000000 --- a/core/c/core/pbuf.c +++ /dev/null @@ -1,1514 +0,0 @@ -/** - * @file - * Packet buffer management - */ - -/** - * @defgroup pbuf Packet buffers (PBUF) - * @ingroup infrastructure - * - * Packets are built from the pbuf data structure. It supports dynamic - * memory allocation for packet contents or can reference externally - * 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). - * - * Example of custom pbuf usage: @ref zerocopyrx - */ - -/* - * 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/pbuf.h" -#include "lwip/stats.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/sys.h" -#include "lwip/netif.h" -#if LWIP_TCP && TCP_QUEUE_OOSEQ -#include "lwip/priv/tcp_priv.h" -#endif -#if LWIP_CHECKSUM_ON_COPY -#include "lwip/inet_chksum.h" -#endif - -#include - -#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) - -static const struct pbuf * -pbuf_skip_const(const struct pbuf *in, u16_t in_offset, u16_t *out_offset); - -#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ -#define PBUF_POOL_IS_EMPTY() -#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ - -#if !NO_SYS -#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL -#include "lwip/tcpip.h" -#define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL() do { \ - if (tcpip_try_callback(pbuf_free_ooseq_callback, NULL) != ERR_OK) { \ - SYS_ARCH_PROTECT(old_level); \ - pbuf_free_ooseq_pending = 0; \ - SYS_ARCH_UNPROTECT(old_level); \ - } } while(0) -#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ -#endif /* !NO_SYS */ - -volatile u8_t pbuf_free_ooseq_pending; -#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty() - -/** - * 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. - */ -#if !NO_SYS -static -#endif /* !NO_SYS */ -void -pbuf_free_ooseq(void) -{ - struct tcp_pcb *pcb; - SYS_ARCH_SET(pbuf_free_ooseq_pending, 0); - - for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { - if (pcb->ooseq != NULL) { - /** 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_free_ooseq(pcb); - return; - } - } -} - -#if !NO_SYS -/** - * Just a callback function for tcpip_callback() that calls pbuf_free_ooseq(). - */ -static void -pbuf_free_ooseq_callback(void *arg) -{ - LWIP_UNUSED_ARG(arg); - pbuf_free_ooseq(); -} -#endif /* !NO_SYS */ - -/** Queue a call to pbuf_free_ooseq if not already queued. */ -static void -pbuf_pool_is_empty(void) -{ -#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL - SYS_ARCH_SET(pbuf_free_ooseq_pending, 1); -#else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ - u8_t queued; - SYS_ARCH_DECL_PROTECT(old_level); - SYS_ARCH_PROTECT(old_level); - queued = pbuf_free_ooseq_pending; - pbuf_free_ooseq_pending = 1; - SYS_ARCH_UNPROTECT(old_level); - - if (!queued) { - /* queue a call to pbuf_free_ooseq if not already queued */ - PBUF_POOL_FREE_OOSEQ_QUEUE_CALL(); - } -#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ -} -#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ - -/* Initialize members of struct pbuf after allocation */ -static void -pbuf_init_alloced_pbuf(struct pbuf *p, void *payload, u16_t tot_len, u16_t len, pbuf_type type, u8_t flags) -{ - p->next = NULL; - p->payload = payload; - p->tot_len = tot_len; - p->len = len; - p->type_internal = (u8_t)type; - p->flags = flags; - p->ref = 1; - p->if_idx = NETIF_NO_INDEX; -} - -/** - * @ingroup pbuf - * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). - * - * The actual memory allocated for the pbuf is determined by the - * layer at which the pbuf is allocated and the requested size - * (from the size parameter). - * - * @param layer 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; - u16_t offset = (u16_t)layer; - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); - - switch (type) { - case PBUF_REF: /* fall through */ - case PBUF_ROM: - p = pbuf_alloc_reference(NULL, length, type); - break; - case PBUF_POOL: { - struct pbuf *q, *last; - u16_t rem_len; /* remaining length */ - p = NULL; - last = NULL; - rem_len = length; - do { - u16_t qlen; - q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); - if (q == NULL) { - PBUF_POOL_IS_EMPTY(); - /* free chain so far allocated */ - if (p) { - pbuf_free(p); - } - /* bail out unsuccessfully */ - return NULL; - } - qlen = LWIP_MIN(rem_len, (u16_t)(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset))); - pbuf_init_alloced_pbuf(q, LWIP_MEM_ALIGN((void *)((u8_t *)q + SIZEOF_STRUCT_PBUF + offset)), - rem_len, qlen, type, 0); - LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", - ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); - LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", - (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); - if (p == NULL) { - /* allocated head of pbuf chain (into p) */ - p = q; - } else { - /* make previous pbuf point to this pbuf */ - last->next = q; - } - last = q; - rem_len = (u16_t)(rem_len - qlen); - offset = 0; - } while (rem_len > 0); - break; - } - case PBUF_RAM: { - u16_t payload_len = (u16_t)(LWIP_MEM_ALIGN_SIZE(offset) + LWIP_MEM_ALIGN_SIZE(length)); - mem_size_t alloc_len = (mem_size_t)(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF) + payload_len); - - /* bug #50040: Check for integer overflow when calculating alloc_len */ - if ((payload_len < LWIP_MEM_ALIGN_SIZE(length)) || - (alloc_len < LWIP_MEM_ALIGN_SIZE(length))) { - return NULL; - } - - /* If pbuf is to be allocated in RAM, allocate memory for it. */ - p = (struct pbuf *)mem_malloc(alloc_len); - if (p == NULL) { - return NULL; - } - pbuf_init_alloced_pbuf(p, LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)), - length, length, type, 0); - LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", - ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); - break; - } - default: - LWIP_ASSERT("pbuf_alloc: erroneous type", 0); - return NULL; - } - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); - return p; -} - -/** - * @ingroup pbuf - * Allocates a pbuf for referenced data. - * Referenced data can be volatile (PBUF_REF) or long-lived (PBUF_ROM). - * - * 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 payload referenced payload - * @param length size of the pbuf's payload - * @param type this parameter decides how and where the pbuf - * should be allocated as follows: - * - * - PBUF_ROM: 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: 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. - * - * @return the allocated pbuf. - */ -struct pbuf * -pbuf_alloc_reference(void *payload, u16_t length, pbuf_type type) -{ - struct pbuf *p; - LWIP_ASSERT("invalid pbuf_type", (type == PBUF_REF) || (type == PBUF_ROM)); - /* 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_reference: Could not allocate MEMP_PBUF for PBUF_%s.\n", - (type == PBUF_ROM) ? "ROM" : "REF")); - return NULL; - } - pbuf_init_alloced_pbuf(p, payload, length, length, type, 0); - return p; -} - - -#if LWIP_SUPPORT_CUSTOM_PBUF -/** - * @ingroup pbuf - * Initialize a custom pbuf (already allocated). - * Example of custom pbuf usage: @ref zerocopyrx - * - * @param l 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. - * ATTENTION: The caller is responsible for correct alignment of this buffer!! - * @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 = (u16_t)l; - void *payload; - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length)); - - 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; - } - - if (payload_mem != NULL) { - payload = (u8_t *)payload_mem + LWIP_MEM_ALIGN_SIZE(offset); - } else { - payload = NULL; - } - pbuf_init_alloced_pbuf(&p->pbuf, payload, length, length, type, PBUF_FLAG_IS_CUSTOM); - return &p->pbuf; -} -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ - -/** - * @ingroup 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 */ - u16_t shrink; - - LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); - - /* 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) */ - shrink = (u16_t)(p->tot_len - new_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 = (u16_t)(rem_len - q->len); - /* decrease total length indicator */ - q->tot_len = (u16_t)(q->tot_len - shrink); - /* 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 (pbuf_match_allocsrc(q, PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP) && (rem_len != q->len) -#if LWIP_SUPPORT_CUSTOM_PBUF - && ((q->flags & PBUF_FLAG_IS_CUSTOM) == 0) -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ - ) { - /* reallocate and adjust the length of the pbuf that will be split */ - q = (struct pbuf *)mem_trim(q, (mem_size_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 reveal headers in the payload. - * @see pbuf_add_header. - * - * @param p pbuf to change the header size. - * @param header_size_increment Number of bytes to increment header size. - * @param force Allow 'header_size_increment > 0' for PBUF_REF/PBUF_ROM types - * - * @return non-zero on failure, zero on success. - * - */ -static u8_t -pbuf_add_header_impl(struct pbuf *p, size_t header_size_increment, u8_t force) -{ - u16_t type_internal; - void *payload; - u16_t increment_magnitude; - - LWIP_ASSERT("p != NULL", p != NULL); - if ((p == NULL) || (header_size_increment > 0xFFFF)) { - return 1; - } - if (header_size_increment == 0) { - return 0; - } - - increment_magnitude = (u16_t)header_size_increment; - /* Do not allow tot_len to wrap as a result. */ - if ((u16_t)(increment_magnitude + p->tot_len) < increment_magnitude) { - return 1; - } - - type_internal = p->type_internal; - - /* pbuf types containing payloads? */ - if (type_internal & PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS) { - /* set new payload pointer */ - payload = (u8_t *)p->payload - header_size_increment; - /* boundary check fails? */ - if ((u8_t *)payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) { - LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, - ("pbuf_add_header: failed as %p < %p (not enough space for new header size)\n", - (void *)payload, (void *)((u8_t *)p + SIZEOF_STRUCT_PBUF))); - /* bail out unsuccessfully */ - return 1; - } - /* pbuf types referring to external payloads? */ - } else { - /* hide a header in the payload? */ - if (force) { - payload = (u8_t *)p->payload - header_size_increment; - } else { - /* cannot expand payload to front (yet!) - * bail out unsuccessfully */ - return 1; - } - } - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_add_header: old %p new %p (%"U16_F")\n", - (void *)p->payload, (void *)payload, increment_magnitude)); - - /* modify pbuf fields */ - p->payload = payload; - p->len = (u16_t)(p->len + increment_magnitude); - p->tot_len = (u16_t)(p->tot_len + increment_magnitude); - - - return 0; -} - -/** - * Adjusts the payload pointer to reveal headers in the payload. - * - * Adjusts the ->payload pointer so that space for a header - * 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. - * If header_size_increment is 0, this function does nothing and returns successful. - * - * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so - * the call will fail. A check is made that the increase in header size does - * not move the payload pointer in front of the start of the buffer. - * - * @return non-zero on failure, zero on success. - * - */ -u8_t -pbuf_add_header(struct pbuf *p, size_t header_size_increment) -{ - return pbuf_add_header_impl(p, header_size_increment, 0); -} - -/** - * Same as @ref pbuf_add_header but does not check if 'header_size > 0' is allowed. - * This is used internally only, to allow PBUF_REF for RX. - */ -u8_t -pbuf_add_header_force(struct pbuf *p, size_t header_size_increment) -{ - return pbuf_add_header_impl(p, header_size_increment, 1); -} - -/** - * Adjusts the payload pointer to hide headers in the payload. - * - * Adjusts the ->payload pointer so that space for a header - * disappears in the pbuf payload. - * - * The ->payload, ->tot_len and ->len fields are adjusted. - * - * @param p pbuf to change the header size. - * @param header_size_decrement Number of bytes to decrement header size which - * decreases the size of the pbuf. - * If header_size_decrement is 0, this function does nothing and returns successful. - * @return non-zero on failure, zero on success. - * - */ -u8_t -pbuf_remove_header(struct pbuf *p, size_t header_size_decrement) -{ - void *payload; - u16_t increment_magnitude; - - LWIP_ASSERT("p != NULL", p != NULL); - if ((p == NULL) || (header_size_decrement > 0xFFFF)) { - return 1; - } - if (header_size_decrement == 0) { - return 0; - } - - increment_magnitude = (u16_t)header_size_decrement; - /* 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;); - - /* remember current payload pointer */ - payload = p->payload; - LWIP_UNUSED_ARG(payload); /* only used in LWIP_DEBUGF below */ - - /* increase payload pointer (guarded by length check above) */ - p->payload = (u8_t *)p->payload + header_size_decrement; - /* modify pbuf length fields */ - p->len = (u16_t)(p->len - increment_magnitude); - p->tot_len = (u16_t)(p->tot_len - increment_magnitude); - - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_remove_header: old %p new %p (%"U16_F")\n", - (void *)payload, (void *)p->payload, increment_magnitude)); - - return 0; -} - -static u8_t -pbuf_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force) -{ - if (header_size_increment < 0) { - return pbuf_remove_header(p, (size_t) - header_size_increment); - } else { - return pbuf_add_header_impl(p, (size_t)header_size_increment, force); - } -} - -/** - * Adjusts the payload pointer to hide or reveal headers in the payload. - * - * Adjusts the ->payload pointer so that space for a header - * (dis)appears in the pbuf payload. - * - * The ->payload, ->tot_len and ->len fields are adjusted. - * - * @param p pbuf to change the header size. - * @param header_size_increment Number of bytes to increment header size which - * increases the size of the pbuf. New space is on the front. - * (Using a negative value decreases the header size.) - * If header_size_increment is 0, this function does nothing and returns successful. - * - * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so - * the call will fail. A check is made that the increase in header size does - * not move the payload pointer in front of the start of the buffer. - * @return non-zero on failure, zero on success. - * - */ -u8_t -pbuf_header(struct pbuf *p, s16_t header_size_increment) -{ - return pbuf_header_impl(p, header_size_increment, 0); -} - -/** - * Same as pbuf_header but does not check if 'header_size > 0' is allowed. - * This is used internally only, to allow PBUF_REF for RX. - */ -u8_t -pbuf_header_force(struct pbuf *p, s16_t header_size_increment) -{ - return pbuf_header_impl(p, header_size_increment, 1); -} - -/** Similar to pbuf_header(-size) but de-refs header pbufs for (size >= p->len) - * - * @param q pbufs to operate on - * @param size The number of bytes to remove from the beginning of the pbuf list. - * While size >= p->len, pbufs are freed. - * ATTENTION: this is the opposite direction as @ref pbuf_header, but - * takes an u16_t not s16_t! - * @return the new head pbuf - */ -struct pbuf * -pbuf_free_header(struct pbuf *q, u16_t size) -{ - struct pbuf *p = q; - u16_t free_left = size; - while (free_left && p) { - if (free_left >= p->len) { - struct pbuf *f = p; - free_left = (u16_t)(free_left - p->len); - p = p->next; - f->next = 0; - pbuf_free(f); - } else { - pbuf_remove_header(p, free_left); - free_left = 0; - } - } - return p; -} - -/** - * @ingroup pbuf - * 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) -{ - u8_t alloc_src; - 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; - - count = 0; - /* de-allocate all consecutive pbufs from the head of the chain that - * obtain a zero reference count after decrementing*/ - while (p != NULL) { - LWIP_PBUF_REF_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)); - alloc_src = pbuf_get_allocsrc(p); -#if LWIP_SUPPORT_CUSTOM_PBUF - /* is this a custom pbuf? */ - if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { - struct pbuf_custom *pc = (struct pbuf_custom *)p; - LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); - pc->custom_free_function(p); - } else -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ - { - /* is this a pbuf from the pool? */ - if (alloc_src == PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF_POOL) { - memp_free(MEMP_PBUF_POOL, p); - /* is this a ROM or RAM referencing pbuf? */ - } else if (alloc_src == PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF) { - memp_free(MEMP_PBUF, p); - /* type == PBUF_RAM */ - } else if (alloc_src == PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP) { - mem_free(p); - } else { - /* @todo: support freeing other types */ - LWIP_ASSERT("invalid pbuf type", 0); - } - } - 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, (u16_t)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 - */ -u16_t -pbuf_clen(const struct pbuf *p) -{ - u16_t len; - - len = 0; - while (p != NULL) { - ++len; - p = p->next; - } - return len; -} - -/** - * @ingroup pbuf - * Increment the reference count of the pbuf. - * - * @param p pbuf to increase reference counter of - * - */ -void -pbuf_ref(struct pbuf *p) -{ - /* pbuf given? */ - if (p != NULL) { - SYS_ARCH_SET(p->ref, (LWIP_PBUF_REF_T)(p->ref + 1)); - LWIP_ASSERT("pbuf ref overflow", p->ref > 0); - } -} - -/** - * @ingroup pbuf - * Concatenate two pbufs (each may be a pbuf chain) and take over - * the caller's reference of the tail pbuf. - * - * @note The caller MAY NOT reference the tail pbuf afterwards. - * Use pbuf_chain() for that purpose. - * - * This function explicitly does not check for tot_len overflow to prevent - * failing to queue too long pbufs. This can produce invalid pbufs, so - * handle with care! - * - * @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 = (u16_t)(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 = (u16_t)(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. - */ -} - -/** - * @ingroup pbuf - * Chain two pbufs (or pbuf chains) together. - * - * The caller MUST call pbuf_free(t) once it has stopped - * using it. Use pbuf_cat() instead if you no longer use t. - * - * @param h head pbuf (chain) - * @param t tail pbuf (chain) - * @note The pbufs MUST belong to the same packet. - * @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 = (u16_t)(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); -} - -/** - * @ingroup pbuf - * 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, const struct pbuf *p_from) -{ - size_t offset_to = 0, offset_from = 0, len; - - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n", - (const void *)p_to, (const void *)p_from)); - - /* 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 { - /* 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); - 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 (offset_to == p_to->len) { - /* on to next p_to (if any) */ - offset_to = 0; - p_to = p_to->next; - LWIP_ERROR("p_to != NULL", (p_to != NULL) || (p_from == NULL), return ERR_ARG;); - } - - if ((p_from != NULL) && (p_from->len == p_from->tot_len)) { - /* don't copy more than one packet! */ - LWIP_ERROR("pbuf_copy() does not allow packet queues!", - (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!", - (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; -} - -/** - * @ingroup pbuf - * Copy (part of) the contents of a packet buffer - * to an application supplied buffer. - * - * @param buf the pbuf from which to copy data - * @param dataptr the application supplied buffer - * @param len length of data to copy (dataptr must be big enough). No more - * than buf->tot_len will be copied, irrespective of len - * @param offset offset into the packet buffer from where to begin copying len bytes - * @return the number of bytes copied, or 0 on failure - */ -u16_t -pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) -{ - 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; -} - -/** - * @ingroup pbuf - * Get part of a pbuf's payload as contiguous memory. The returned memory is - * either a pointer into the pbuf's payload or, if split over multiple pbufs, - * a copy into the user-supplied buffer. - * - * @param p the pbuf from which to copy data - * @param buffer the application supplied buffer - * @param bufsize size of 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 - */ -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; -} - -#if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE -/** - * This method modifies a 'pbuf chain', so that its total length is - * smaller than 64K. The remainder of the original pbuf chain is stored - * in *rest. - * This function never creates new pbufs, but splits an existing chain - * in two parts. The tot_len of the modified packet queue will likely be - * smaller than 64K. - * 'packet queues' are not supported by this function. - * - * @param p the pbuf queue to be split - * @param rest pointer to store the remainder (after the first 64K) - */ -void pbuf_split_64k(struct pbuf *p, struct pbuf **rest) -{ - *rest = NULL; - if ((p != NULL) && (p->next != NULL)) { - u16_t tot_len_front = p->len; - struct pbuf *i = p; - struct pbuf *r = p->next; - - /* continue until the total length (summed up as u16_t) overflows */ - while ((r != NULL) && ((u16_t)(tot_len_front + r->len) >= tot_len_front)) { - tot_len_front = (u16_t)(tot_len_front + r->len); - i = r; - r = r->next; - } - /* i now points to last packet of the first segment. Set next - pointer to NULL */ - i->next = NULL; - - if (r != NULL) { - /* Update the tot_len field in the first part */ - for (i = p; i != NULL; i = i->next) { - i->tot_len = (u16_t)(i->tot_len - r->tot_len); - LWIP_ASSERT("tot_len/len mismatch in last pbuf", - (i->next != NULL) || (i->tot_len == i->len)); - } - if (p->flags & PBUF_FLAG_TCP_FIN) { - r->flags |= PBUF_FLAG_TCP_FIN; - } - - /* tot_len field in rest does not need modifications */ - /* reference counters do not need modifications */ - *rest = r; - } - } -} -#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - -/* Actual implementation of pbuf_skip() but returning const pointer... */ -static const struct pbuf * -pbuf_skip_const(const struct pbuf *in, u16_t in_offset, u16_t *out_offset) -{ - u16_t offset_left = in_offset; - const struct pbuf *q = in; - - /* get the correct pbuf */ - while ((q != NULL) && (q->len <= offset_left)) { - offset_left = (u16_t)(offset_left - q->len); - q = q->next; - } - if (out_offset != NULL) { - *out_offset = offset_left; - } - return q; -} - -/** - * @ingroup pbuf - * Skip a number of bytes at the start of a pbuf - * - * @param in input pbuf - * @param in_offset offset to skip - * @param out_offset resulting offset in the returned pbuf - * @return the pbuf in the queue where the offset is - */ -struct pbuf * -pbuf_skip(struct pbuf *in, u16_t in_offset, u16_t *out_offset) -{ - const struct pbuf *out = pbuf_skip_const(in, in_offset, out_offset); - return LWIP_CONST_CAST(struct pbuf *, out); -} - -/** - * @ingroup pbuf - * Copy application supplied data into a pbuf. - * This function can only be used to copy the equivalent of buf->tot_len data. - * - * @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; - size_t buf_copy_len; - size_t total_copy_len = len; - size_t copied_total = 0; - - LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return ERR_ARG;); - LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return ERR_ARG;); - LWIP_ERROR("pbuf_take: buf not large enough", (buf->tot_len >= len), return ERR_MEM;); - - 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, &((const 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; -} - -/** - * @ingroup pbuf - * Same as pbuf_take() but puts data at an offset - * - * @param buf pbuf to fill with data - * @param dataptr application supplied data buffer - * @param len length of the application supplied data buffer - * @param offset offset in pbuf where to copy dataptr to - * - * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough - */ -err_t -pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset) -{ - u16_t target_offset; - struct pbuf *q = pbuf_skip(buf, offset, &target_offset); - - /* return requested data if pbuf is OK */ - if ((q != NULL) && (q->tot_len >= target_offset + len)) { - u16_t remaining_len = len; - const u8_t *src_ptr = (const u8_t *)dataptr; - /* copy the part that goes into the first pbuf */ - u16_t first_copy_len; - LWIP_ASSERT("check pbuf_skip result", target_offset < q->len); - first_copy_len = (u16_t)LWIP_MIN(q->len - target_offset, len); - MEMCPY(((u8_t *)q->payload) + target_offset, dataptr, first_copy_len); - remaining_len = (u16_t)(remaining_len - first_copy_len); - src_ptr += first_copy_len; - if (remaining_len > 0) { - return pbuf_take(q->next, src_ptr, remaining_len); - } - return ERR_OK; - } - return ERR_MEM; -} - -/** - * @ingroup pbuf - * Creates a single pbuf out of a queue of pbufs. - * - * @remark: Either the source pbuf 'p' is freed by this function or the original - * 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; - if (p->next == NULL) { - return p; - } - q = pbuf_clone(layer, PBUF_RAM, p); - if (q == NULL) { - /* @todo: what do we do now? */ - return p; - } - pbuf_free(p); - return q; -} - -/** - * @ingroup pbuf - * Allocates a new pbuf of same length (via pbuf_alloc()) and copies the source - * pbuf into this new pbuf (using pbuf_copy()). - * - * @param layer pbuf_layer of the new pbuf - * @param type this parameter decides how and where the pbuf should be allocated - * (@see pbuf_alloc()) - * @param p the source pbuf - * - * @return a new pbuf or NULL if allocation fails - */ -struct pbuf * -pbuf_clone(pbuf_layer layer, pbuf_type type, struct pbuf *p) -{ - struct pbuf *q; - err_t err; - q = pbuf_alloc(layer, p->tot_len, type); - if (q == NULL) { - return NULL; - } - err = pbuf_copy(q, p); - LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */ - LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); - 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 */ - -/** - * @ingroup pbuf - * 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(const struct pbuf *p, u16_t offset) -{ - int ret = pbuf_try_get_at(p, offset); - if (ret >= 0) { - return (u8_t)ret; - } - return 0; -} - -/** - * @ingroup pbuf - * Get one byte from the specified position in a pbuf - * - * @param p pbuf to parse - * @param offset offset into p of the byte to return - * @return byte at an offset into p [0..0xFF] OR negative if 'offset' >= p->tot_len - */ -int -pbuf_try_get_at(const struct pbuf *p, u16_t offset) -{ - u16_t q_idx; - const struct pbuf *q = pbuf_skip_const(p, offset, &q_idx); - - /* return requested data if pbuf is OK */ - if ((q != NULL) && (q->len > q_idx)) { - return ((u8_t *)q->payload)[q_idx]; - } - return -1; -} - -/** - * @ingroup pbuf - * Put one byte to the specified position in a pbuf - * WARNING: silently ignores offset >= p->tot_len - * - * @param p pbuf to fill - * @param offset offset into p of the byte to write - * @param data byte to write at an offset into p - */ -void -pbuf_put_at(struct pbuf *p, u16_t offset, u8_t data) -{ - u16_t q_idx; - struct pbuf *q = pbuf_skip(p, offset, &q_idx); - - /* write requested data if pbuf is OK */ - if ((q != NULL) && (q->len > q_idx)) { - ((u8_t *)q->payload)[q_idx] = data; - } -} - -/** - * @ingroup pbuf - * Compare pbuf contents at specified offset with memory s2, both of length n - * - * @param p pbuf to compare - * @param offset offset into p at which to start comparing - * @param s2 buffer to compare - * @param n length of buffer to compare - * @return zero if equal, nonzero otherwise - * (0xffff if p is too short, diffoffset+1 otherwise) - */ -u16_t -pbuf_memcmp(const struct pbuf *p, u16_t offset, const void *s2, u16_t n) -{ - u16_t start = offset; - const struct pbuf *q = p; - u16_t i; - - /* pbuf long enough to perform check? */ - if (p->tot_len < (offset + n)) { - return 0xffff; - } - - /* get the correct pbuf from chain. We know it succeeds because of p->tot_len check above. */ - while ((q != NULL) && (q->len <= start)) { - start = (u16_t)(start - q->len); - q = q->next; - } - - /* return requested data if pbuf is OK */ - for (i = 0; i < n; i++) { - /* We know pbuf_get_at() succeeds because of p->tot_len check above. */ - u8_t a = pbuf_get_at(q, (u16_t)(start + i)); - u8_t b = ((const u8_t *)s2)[i]; - if (a != b) { - return (u16_t)LWIP_MIN(i + 1, 0xFFFF); - } - } - return 0; -} - -/** - * @ingroup pbuf - * 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(const struct pbuf *p, const void *mem, u16_t mem_len, u16_t start_offset) -{ - u16_t i; - u16_t max_cmp_start = (u16_t)(p->tot_len - mem_len); - if (p->tot_len >= mem_len + start_offset) { - for (i = start_offset; i <= max_cmp_start; i++) { - u16_t plus = pbuf_memcmp(p, i, mem, mem_len); - if (plus == 0) { - return i; - } - } - } - 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(const struct pbuf *p, const char *substr) -{ - size_t substr_len; - if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) { - return 0xFFFF; - } - substr_len = strlen(substr); - if (substr_len >= 0xFFFF) { - return 0xFFFF; - } - return pbuf_memfind(p, substr, (u16_t)substr_len, 0); -} diff --git a/core/c/core/raw.c b/core/c/core/raw.c deleted file mode 100755 index 7a42432..0000000 --- a/core/c/core/raw.c +++ /dev/null @@ -1,671 +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.\n - * See also @ref raw_raw - * - * @defgroup raw_raw RAW - * @ingroup callbackstyle_api - * Implementation of raw protocol PCBs for low-level handling of - * different types of protocols besides (or overriding) those - * already available in lwIP.\n - * @see @ref api - */ - -/* - * 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/priv/raw_priv.h" -#include "lwip/stats.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/inet_chksum.h" - -#include - -/** The list of RAW PCBs */ -static struct raw_pcb *raw_pcbs; - -static u8_t -raw_input_local_match(struct raw_pcb *pcb, u8_t broadcast) -{ - LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ - - /* check if PCB is bound to specific netif */ - if ((pcb->netif_idx != NETIF_NO_INDEX) && - (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { - return 0; - } - -#if LWIP_IPV4 && LWIP_IPV6 - /* Dual-stack: PCBs listening to any IP type also listen to any IP address */ - if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { -#if IP_SOF_BROADCAST_RECV - if ((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) { - return 0; - } -#endif /* IP_SOF_BROADCAST_RECV */ - return 1; - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - - /* Only need to check PCB if incoming IP version matches PCB IP version */ - if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) { -#if LWIP_IPV4 - /* Special case: IPv4 broadcast: receive all broadcasts - * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */ - if (broadcast != 0) { -#if IP_SOF_BROADCAST_RECV - if (ip_get_option(pcb, SOF_BROADCAST)) -#endif /* IP_SOF_BROADCAST_RECV */ - { - if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip))) { - return 1; - } - } - } else -#endif /* LWIP_IPV4 */ - /* Handle IPv4 and IPv6: catch all or exact match */ - if (ip_addr_isany(&pcb->local_ip) || - ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { - return 1; - } - } - - return 0; -} - -/** - * 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). - * - */ -raw_input_state_t -raw_input(struct pbuf *p, struct netif *inp) -{ - struct raw_pcb *pcb, *prev; - s16_t proto; - raw_input_state_t ret = RAW_INPUT_NONE; - u8_t broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); - - LWIP_UNUSED_ARG(inp); - -#if LWIP_IPV6 -#if LWIP_IPV4 - if (IP_HDR_GET_VERSION(p->payload) == 6) -#endif /* LWIP_IPV4 */ - { - struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; - proto = IP6H_NEXTH(ip6hdr); - } -#if LWIP_IPV4 - else -#endif /* LWIP_IPV4 */ -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 - { - proto = IPH_PROTO((struct ip_hdr *)p->payload); - } -#endif /* LWIP_IPV4 */ - - 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 (pcb != NULL) { - if ((pcb->protocol == proto) && raw_input_local_match(pcb, broadcast) && - (((pcb->flags & RAW_FLAGS_CONNECTED) == 0) || - ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { - /* receive callback function available? */ - if (pcb->recv != NULL) { - u8_t eaten; -#ifndef LWIP_NOASSERT - void *old_payload = p->payload; -#endif - ret = RAW_INPUT_DELIVERED; - /* the receive callback function did not eat the packet? */ - eaten = pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()); - if (eaten != 0) { - /* receive function ate the packet */ - p = NULL; - 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; - } - return RAW_INPUT_EATEN; - } else { - /* sanity-check that the receive callback did not alter the pbuf */ - LWIP_ASSERT("raw pcb recv callback altered pbuf payload pointer without eating packet", - p->payload == old_payload); - } - } - /* no receive callback function was set for this raw PCB */ - } - /* drop the packet */ - prev = pcb; - pcb = pcb->next; - } - return ret; -} - -/** - * @ingroup raw_raw - * 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 IP4_ADDR_ANY to - * bind to all local interfaces. - * - * @return lwIP error code. - * - ERR_OK. Successful. No error occurred. - * - ERR_USE. The specified IP address is already bound to by - * another RAW PCB. - * - * @see raw_disconnect() - */ -err_t -raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr) -{ - LWIP_ASSERT_CORE_LOCKED(); - if ((pcb == NULL) || (ipaddr == NULL)) { - return ERR_VAL; - } - ip_addr_set_ipaddr(&pcb->local_ip, ipaddr); -#if LWIP_IPV6 && LWIP_IPV6_SCOPES - /* If the given IP address should have a zone but doesn't, assign one now. - * This is legacy support: scope-aware callers should always provide properly - * zoned source addresses. */ - if (IP_IS_V6(&pcb->local_ip) && - ip6_addr_lacks_zone(ip_2_ip6(&pcb->local_ip), IP6_UNKNOWN)) { - ip6_addr_select_zone(ip_2_ip6(&pcb->local_ip), ip_2_ip6(&pcb->local_ip)); - } -#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ - return ERR_OK; -} - -/** - * @ingroup raw_raw - * Bind an RAW PCB to a specific netif. - * After calling this function, all packets received via this PCB - * are guaranteed to have come in via the specified netif, and all - * outgoing packets will go out via the specified netif. - * - * @param pcb RAW PCB to be bound with netif. - * @param netif netif to bind to. Can be NULL. - * - * @see raw_disconnect() - */ -void -raw_bind_netif(struct raw_pcb *pcb, const struct netif *netif) -{ - LWIP_ASSERT_CORE_LOCKED(); - if (netif != NULL) { - pcb->netif_idx = netif_get_index(netif); - } else { - pcb->netif_idx = NETIF_NO_INDEX; - } -} - -/** - * @ingroup raw_raw - * 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 -raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr) -{ - LWIP_ASSERT_CORE_LOCKED(); - if ((pcb == NULL) || (ipaddr == NULL)) { - return ERR_VAL; - } - ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr); -#if LWIP_IPV6 && LWIP_IPV6_SCOPES - /* If the given IP address should have a zone but doesn't, assign one now, - * using the bound address to make a more informed decision when possible. */ - if (IP_IS_V6(&pcb->remote_ip) && - ip6_addr_lacks_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNKNOWN)) { - ip6_addr_select_zone(ip_2_ip6(&pcb->remote_ip), ip_2_ip6(&pcb->local_ip)); - } -#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ - raw_set_flags(pcb, RAW_FLAGS_CONNECTED); - return ERR_OK; -} - -/** - * @ingroup raw_raw - * Disconnect a RAW PCB. - * - * @param pcb the raw pcb to disconnect. - */ -void -raw_disconnect(struct raw_pcb *pcb) -{ - LWIP_ASSERT_CORE_LOCKED(); - /* reset remote address association */ -#if LWIP_IPV4 && LWIP_IPV6 - if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { - ip_addr_copy(pcb->remote_ip, *IP_ANY_TYPE); - } else { -#endif - ip_addr_set_any(IP_IS_V6_VAL(pcb->remote_ip), &pcb->remote_ip); -#if LWIP_IPV4 && LWIP_IPV6 - } -#endif - pcb->netif_idx = NETIF_NO_INDEX; - /* mark PCB as unconnected */ - raw_clear_flags(pcb, RAW_FLAGS_CONNECTED); -} - -/** - * @ingroup raw_raw - * 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. - */ -void -raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) -{ - LWIP_ASSERT_CORE_LOCKED(); - /* remember recv() callback and user data */ - pcb->recv = recv; - pcb->recv_arg = recv_arg; -} - -/** - * @ingroup raw_raw - * Send the raw IP packet to the given address. An IP header will be prepended - * to the packet, unless the RAW_FLAGS_HDRINCL flag is set on the PCB. In that - * case, the packet must include an IP header, which will then be sent as is. - * - * @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 -raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) -{ - struct netif *netif; - const ip_addr_t *src_ip; - - if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) { - return ERR_VAL; - } - - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); - - if (pcb->netif_idx != NETIF_NO_INDEX) { - netif = netif_get_by_index(pcb->netif_idx); - } else { -#if LWIP_MULTICAST_TX_OPTIONS - netif = NULL; - if (ip_addr_ismulticast(ipaddr)) { - /* For multicast-destined packets, use the user-provided interface index to - * determine the outgoing interface, if an interface index is set and a - * matching netif can be found. Otherwise, fall back to regular routing. */ - netif = netif_get_by_index(pcb->mcast_ifindex); - } - - if (netif == NULL) -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - { - netif = ip_route(&pcb->local_ip, ipaddr); - } - } - - if (netif == NULL) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); - ip_addr_debug_print(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ipaddr); - return ERR_RTE; - } - - if (ip_addr_isany(&pcb->local_ip) || ip_addr_ismulticast(&pcb->local_ip)) { - /* use outgoing network interface IP address as source address */ - src_ip = ip_netif_get_local_ip(netif, ipaddr); -#if LWIP_IPV6 - if (src_ip == NULL) { - return ERR_RTE; - } -#endif /* LWIP_IPV6 */ - } else { - /* use RAW PCB local IP address as source address */ - src_ip = &pcb->local_ip; - } - - return raw_sendto_if_src(pcb, p, ipaddr, netif, src_ip); -} - -/** - * @ingroup raw_raw - * Send the raw IP packet to the given address, using a particular outgoing - * netif and source IP address. An IP header will be prepended to the packet, - * unless the RAW_FLAGS_HDRINCL flag is set on the PCB. In that case, the - * packet must include an IP header, which will then be sent as is. - * - * @param pcb RAW PCB used to send the data - * @param p chain of pbufs to be sent - * @param dst_ip destination IP address - * @param netif the netif used for sending - * @param src_ip source IP address - */ -err_t -raw_sendto_if_src(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, - struct netif *netif, const ip_addr_t *src_ip) -{ - err_t err; - struct pbuf *q; /* q will be sent down the stack */ - u16_t header_size; - u8_t ttl; - - LWIP_ASSERT_CORE_LOCKED(); - - if ((pcb == NULL) || (dst_ip == NULL) || (netif == NULL) || (src_ip == NULL) || - !IP_ADDR_PCB_VERSION_MATCH(pcb, src_ip) || !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { - return ERR_VAL; - } - - header_size = ( -#if LWIP_IPV4 && LWIP_IPV6 - IP_IS_V6(dst_ip) ? IP6_HLEN : IP_HLEN); -#elif LWIP_IPV4 - IP_HLEN); -#else - IP6_HLEN); -#endif - - /* Handle the HDRINCL option as an exception: none of the code below applies - * to this case, and sending the packet needs to be done differently too. */ - if (pcb->flags & RAW_FLAGS_HDRINCL) { - /* A full header *must* be present in the first pbuf of the chain, as the - * output routines may access its fields directly. */ - if (p->len < header_size) { - return ERR_VAL; - } - /* @todo multicast loop support, if at all desired for this scenario.. */ - NETIF_SET_HINTS(netif, &pcb->netif_hints); - err = ip_output_if_hdrincl(p, src_ip, dst_ip, netif); - NETIF_RESET_HINTS(netif); - return err; - } - - /* packet too large to add an IP header without causing an overflow? */ - if ((u16_t)(p->tot_len + header_size) < p->tot_len) { - return ERR_MEM; - } - /* not enough space to add an IP header to first pbuf in given p chain? */ - if (pbuf_add_header(p, header_size)) { - /* allocate header in new pbuf */ - q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); - /* new header pbuf could not be allocated? */ - if (q == NULL) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 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_remove_header(q, header_size)) { - LWIP_ASSERT("Can't restore header we just removed!", 0); - return ERR_MEM; - } - } - -#if IP_SOF_BROADCAST - if (IP_IS_V4(dst_ip)) { - /* broadcast filter? */ - if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(dst_ip, 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 */ - - /* Multicast Loop? */ -#if LWIP_MULTICAST_TX_OPTIONS - if (((pcb->flags & RAW_FLAGS_MULTICAST_LOOP) != 0) && ip_addr_ismulticast(dst_ip)) { - q->flags |= PBUF_FLAG_MCASTLOOP; - } -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - -#if LWIP_IPV6 - /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542, - compute the checksum and update the checksum in the payload. */ - if (IP_IS_V6(dst_ip) && pcb->chksum_reqd) { - u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ip_2_ip6(src_ip), ip_2_ip6(dst_ip)); - LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2)); - SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t)); - } -#endif - - /* Determine TTL to use */ -#if LWIP_MULTICAST_TX_OPTIONS - ttl = (ip_addr_ismulticast(dst_ip) ? raw_get_multicast_ttl(pcb) : pcb->ttl); -#else /* LWIP_MULTICAST_TX_OPTIONS */ - ttl = pcb->ttl; -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - - NETIF_SET_HINTS(netif, &pcb->netif_hints); - err = ip_output_if(q, src_ip, dst_ip, ttl, pcb->tos, pcb->protocol, netif); - NETIF_RESET_HINTS(netif); - - /* did we chain a header earlier? */ - if (q != p) { - /* free the header */ - pbuf_free(q); - } - return err; -} - -/** - * @ingroup raw_raw - * 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 -raw_send(struct raw_pcb *pcb, struct pbuf *p) -{ - return raw_sendto(pcb, p, &pcb->remote_ip); -} - -/** - * @ingroup raw_raw - * 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 -raw_remove(struct raw_pcb *pcb) -{ - struct raw_pcb *pcb2; - LWIP_ASSERT_CORE_LOCKED(); - /* 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; - break; - } - } - } - memp_free(MEMP_RAW_PCB, pcb); -} - -/** - * @ingroup raw_raw - * 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 * -raw_new(u8_t proto) -{ - struct raw_pcb *pcb; - - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n")); - LWIP_ASSERT_CORE_LOCKED(); - - pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB); - /* could allocate RAW PCB? */ - if (pcb != NULL) { - /* initialize PCB to all zeroes */ - memset(pcb, 0, sizeof(struct raw_pcb)); - pcb->protocol = proto; - pcb->ttl = RAW_TTL; -#if LWIP_MULTICAST_TX_OPTIONS - raw_set_multicast_ttl(pcb, RAW_TTL); -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - pcb->next = raw_pcbs; - raw_pcbs = pcb; - } - return pcb; -} - -/** - * @ingroup raw_raw - * Create a RAW PCB for specific IP type. - * - * @return The RAW PCB which was created. NULL if the PCB data structure - * could not be allocated. - * - * @param type IP address type, see @ref lwip_ip_addr_type definitions. - * If you want to listen to IPv4 and IPv6 (dual-stack) packets, - * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. - * @param proto the protocol number (next header) of the IPv6 packet payload - * (e.g. IP6_NEXTH_ICMP6) - * - * @see raw_remove() - */ -struct raw_pcb * -raw_new_ip_type(u8_t type, u8_t proto) -{ - struct raw_pcb *pcb; - LWIP_ASSERT_CORE_LOCKED(); - pcb = raw_new(proto); -#if LWIP_IPV4 && LWIP_IPV6 - if (pcb != NULL) { - IP_SET_TYPE_VAL(pcb->local_ip, type); - IP_SET_TYPE_VAL(pcb->remote_ip, type); - } -#else /* LWIP_IPV4 && LWIP_IPV6 */ - LWIP_UNUSED_ARG(type); -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - return pcb; -} - -/** This function is called from netif.c when address is changed - * - * @param old_addr IP address of the netif before change - * @param new_addr IP address of the netif after change - */ -void raw_netif_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) -{ - struct raw_pcb *rpcb; - - if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) { - for (rpcb = raw_pcbs; rpcb != NULL; rpcb = rpcb->next) { - /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&rpcb->local_ip, old_addr)) { - /* The PCB is bound to the old ipaddr and - * is set to bound to the new one instead */ - ip_addr_copy(rpcb->local_ip, *new_addr); - } - } - } -} - -#endif /* LWIP_RAW */ diff --git a/core/c/core/stats.c b/core/c/core/stats.c deleted file mode 100755 index 4602842..0000000 --- a/core/c/core/stats.c +++ /dev/null @@ -1,169 +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 "lwip/debug.h" - -#include - -struct stats_ lwip_stats; - -void -stats_init(void) -{ -#ifdef LWIP_DEBUG -#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, const char *name) -{ - LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); - LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit)); - LWIP_PLATFORM_DIAG(("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 || MLD6_STATS -void -stats_display_igmp(struct stats_igmp *igmp, const char *name) -{ - LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); - LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit)); - LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv)); - LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop)); - LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr)); - LWIP_PLATFORM_DIAG(("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\t", igmp->rx_group)); - LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n\t", 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", igmp->tx_report)); -} -#endif /* IGMP_STATS || MLD6_STATS */ - -#if MEM_STATS || MEMP_STATS -void -stats_display_mem(struct stats_mem *mem, const char *name) -{ - LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name)); - LWIP_PLATFORM_DIAG(("avail: %"MEM_SIZE_F"\n\t", mem->avail)); - LWIP_PLATFORM_DIAG(("used: %"MEM_SIZE_F"\n\t", mem->used)); - LWIP_PLATFORM_DIAG(("max: %"MEM_SIZE_F"\n\t", mem->max)); - LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n", mem->err)); -} - -#if MEMP_STATS -void -stats_display_memp(struct stats_mem *mem, int idx) -{ - if (idx < MEMP_MAX) { - stats_display_mem(mem, mem->name); - } -} -#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: %"STAT_COUNTER_F"\n\t", sys->sem.used)); - LWIP_PLATFORM_DIAG(("sem.max: %"STAT_COUNTER_F"\n\t", sys->sem.max)); - LWIP_PLATFORM_DIAG(("sem.err: %"STAT_COUNTER_F"\n\t", sys->sem.err)); - LWIP_PLATFORM_DIAG(("mutex.used: %"STAT_COUNTER_F"\n\t", sys->mutex.used)); - LWIP_PLATFORM_DIAG(("mutex.max: %"STAT_COUNTER_F"\n\t", sys->mutex.max)); - LWIP_PLATFORM_DIAG(("mutex.err: %"STAT_COUNTER_F"\n\t", sys->mutex.err)); - LWIP_PLATFORM_DIAG(("mbox.used: %"STAT_COUNTER_F"\n\t", sys->mbox.used)); - LWIP_PLATFORM_DIAG(("mbox.max: %"STAT_COUNTER_F"\n\t", sys->mbox.max)); - LWIP_PLATFORM_DIAG(("mbox.err: %"STAT_COUNTER_F"\n", sys->mbox.err)); -} -#endif /* SYS_STATS */ - -void -stats_display(void) -{ - s16_t i; - - LINK_STATS_DISPLAY(); - ETHARP_STATS_DISPLAY(); - IPFRAG_STATS_DISPLAY(); - IP6_FRAG_STATS_DISPLAY(); - IP_STATS_DISPLAY(); - ND6_STATS_DISPLAY(); - IP6_STATS_DISPLAY(); - IGMP_STATS_DISPLAY(); - MLD6_STATS_DISPLAY(); - ICMP_STATS_DISPLAY(); - ICMP6_STATS_DISPLAY(); - UDP_STATS_DISPLAY(); - TCP_STATS_DISPLAY(); - MEM_STATS_DISPLAY(); - for (i = 0; i < MEMP_MAX; i++) { - MEMP_STATS_DISPLAY(i); - } - SYS_STATS_DISPLAY(); -} -#endif /* LWIP_STATS_DISPLAY */ - -#endif /* LWIP_STATS */ - diff --git a/core/c/core/sys.c b/core/c/core/sys.c deleted file mode 100755 index b95f4bd..0000000 --- a/core/c/core/sys.c +++ /dev/null @@ -1,148 +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 - * - */ - -/** - * @defgroup sys_layer Porting (system abstraction layer) - * @ingroup lwip - * - * @defgroup sys_os OS abstraction layer - * @ingroup sys_layer - * No need to implement functions in this section in NO_SYS mode. - * The OS-specific code should be implemented in arch/sys_arch.h - * and sys_arch.c of your port. - * - * The operating system emulation layer provides a common interface - * between the lwIP code and the underlying operating system kernel. The - * general idea is that porting lwIP to new architectures requires only - * small changes to a few header files and a new sys_arch - * implementation. It is also possible to do a sys_arch implementation - * that does not rely on any underlying operating system. - * - * The sys_arch provides semaphores, mailboxes and mutexes to lwIP. For the full - * lwIP functionality, multiple threads support can be implemented in the - * sys_arch, but this is not required for the basic lwIP - * functionality. Timer scheduling is implemented in lwIP, but can be implemented - * by the sys_arch port (LWIP_TIMERS_CUSTOM==1). - * - * In addition to the source file providing the functionality of sys_arch, - * the OS emulation layer must provide several header files defining - * macros used throughout lwip. The files required and the macros they - * must define are listed below the sys_arch description. - * - * Since lwIP 1.4.0, semaphore, mutexes and mailbox functions are prototyped in a way that - * allows both using pointers or actual OS structures to be used. This way, memory - * required for such types can be either allocated in place (globally or on the - * stack) or on the heap (allocated internally in the "*_new()" functions). - * - * Note: - * ----- - * Be careful with using mem_malloc() in sys_arch. When malloc() refers to - * mem_malloc() you can run into a circular function call problem. In mem.c - * mem_init() tries to allocate a semaphore using mem_malloc, which of course - * can't be performed when sys_arch uses mem_malloc. - * - * @defgroup sys_sem Semaphores - * @ingroup sys_os - * Semaphores can be either counting or binary - lwIP works with both - * kinds. - * Semaphores are represented by the type "sys_sem_t" which is typedef'd - * in the sys_arch.h file. Mailboxes are equivalently represented by the - * type "sys_mbox_t". Mutexes are represented by the type "sys_mutex_t". - * lwIP does not place any restrictions on how these types are represented - * internally. - * - * @defgroup sys_mutex Mutexes - * @ingroup sys_os - * Mutexes are recommended to correctly handle priority inversion, - * especially if you use LWIP_CORE_LOCKING . - * - * @defgroup sys_mbox Mailboxes - * @ingroup sys_os - * Mailboxes should be implemented as a queue which allows multiple messages - * to be posted (implementing as a rendez-vous point where only one message can be - * posted at a time can have a highly negative impact on performance). A message - * in a mailbox is just a pointer, nothing more. - * - * @defgroup sys_time Time - * @ingroup sys_layer - * - * @defgroup sys_prot Critical sections - * @ingroup sys_layer - * Used to protect short regions of code against concurrent access. - * - Your system is a bare-metal system (probably with an RTOS) - * and interrupts are under your control: - * Implement this as LockInterrupts() / UnlockInterrupts() - * - Your system uses an RTOS with deferred interrupt handling from a - * worker thread: Implement as a global mutex or lock/unlock scheduler - * - Your system uses a high-level OS with e.g. POSIX signals: - * Implement as a global mutex - * - * @defgroup sys_misc Misc - * @ingroup sys_os - */ - -#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 - -#ifndef sys_msleep -/** - * 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 /* sys_msleep */ - -#endif /* !NO_SYS */ diff --git a/core/c/core/tcp.c b/core/c/core/tcp.c deleted file mode 100755 index 2ff37ef..0000000 --- a/core/c/core/tcp.c +++ /dev/null @@ -1,2686 +0,0 @@ -/** - * @file - * Transmission Control Protocol for IP - * See also @ref tcp_raw - * - * @defgroup tcp_raw TCP - * @ingroup callbackstyle_api - * Transmission Control Protocol for IP\n - * @see @ref api - * - * Common functions for the TCP implementation, such as functions - * 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.\n - * - * TCP connection setup - * -------------------- - * The functions used for setting up connections is similar to that of - * the sequential API and of the BSD socket API. A new TCP connection - * identifier (i.e., a protocol control block - PCB) is created with the - * tcp_new() function. This PCB can then be either set to listen for new - * incoming connections or be explicitly connected to another host. - * - tcp_new() - * - tcp_bind() - * - tcp_listen() and tcp_listen_with_backlog() - * - tcp_accept() - * - tcp_connect() - * - * Sending TCP data - * ---------------- - * TCP data is sent by enqueueing the data with a call to tcp_write() and - * triggering to send by calling tcp_output(). When the data is successfully - * transmitted to the remote host, the application will be notified with a - * call to a specified callback function. - * - tcp_write() - * - tcp_output() - * - tcp_sent() - * - * Receiving TCP data - * ------------------ - * TCP data reception is callback based - an application specified - * callback function is called when new data arrives. When the - * application has taken the data, it has to call the tcp_recved() - * function to indicate that TCP can advertise increase the receive - * window. - * - tcp_recv() - * - tcp_recved() - * - * Application polling - * ------------------- - * When a connection is idle (i.e., no data is either transmitted or - * received), lwIP will repeatedly poll the application by calling a - * specified callback function. This can be used either as a watchdog - * timer for killing connections that have stayed idle for too long, or - * as a method of waiting for memory to become available. For instance, - * if a call to tcp_write() has failed because memory wasn't available, - * the application may use the polling functionality to call tcp_write() - * again when the connection has been idle for a while. - * - tcp_poll() - * - * Closing and aborting connections - * -------------------------------- - * - tcp_close() - * - tcp_abort() - * - tcp_err() - * - */ - -/* - * 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/tcp.h" -#include "lwip/priv/tcp_priv.h" -#include "lwip/debug.h" -#include "lwip/stats.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/nd6.h" - -#include - -#ifdef LWIP_HOOK_FILENAME -#include LWIP_HOOK_FILENAME -#endif - -#ifndef TCP_LOCAL_PORT_RANGE_START -/* From http://www.iana.org/assignments/port-numbers: - "The Dynamic and/or Private Ports are those from 49152 through 65535" */ -#define TCP_LOCAL_PORT_RANGE_START 0xc000 -#define TCP_LOCAL_PORT_RANGE_END 0xffff -#define TCP_ENSURE_LOCAL_PORT_RANGE(port) ((u16_t)(((port) & (u16_t)~TCP_LOCAL_PORT_RANGE_START) + TCP_LOCAL_PORT_RANGE_START)) -#endif - -#if LWIP_TCP_KEEPALIVE -#define TCP_KEEP_DUR(pcb) ((pcb)->keep_cnt * (pcb)->keep_intvl) -#define TCP_KEEP_INTVL(pcb) ((pcb)->keep_intvl) -#else /* LWIP_TCP_KEEPALIVE */ -#define TCP_KEEP_DUR(pcb) TCP_MAXIDLE -#define TCP_KEEP_INTVL(pcb) TCP_KEEPINTVL_DEFAULT -#endif /* LWIP_TCP_KEEPALIVE */ - -/* As initial send MSS, we use TCP_MSS but limit it to 536. */ -#if TCP_MSS > 536 -#define INITIAL_MSS 536 -#else -#define INITIAL_MSS TCP_MSS -#endif - -static const char *const tcp_state_str[] = { - "CLOSED", - "LISTEN", - "SYN_SENT", - "SYN_RCVD", - "ESTABLISHED", - "FIN_WAIT_1", - "FIN_WAIT_2", - "CLOSE_WAIT", - "CLOSING", - "LAST_ACK", - "TIME_WAIT" -}; - -/* last local TCP port */ -static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; - -/* Incremented every coarse grained timer shot (typically every 500 ms). */ -u32_t tcp_ticks; -static const u8_t tcp_backoff[13] = -{ 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; -/* Times per slowtmr hits */ -static const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; - -/* The TCP PCB lists. */ - -/** List of all TCP PCBs bound but not yet (connected || listening) */ -struct tcp_pcb *tcp_bound_pcbs; -/** 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; - -/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ -struct tcp_pcb **const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, - &tcp_active_pcbs, &tcp_tw_pcbs -}; - -u8_t tcp_active_pcbs_changed; - -/** Timer counter to handle calling slow-timer from tcp_tmr() */ -static u8_t tcp_timer; -static u8_t tcp_timer_ctr; -static u16_t tcp_new_port(void); - -static err_t tcp_close_shutdown_fin(struct tcp_pcb *pcb); -#if LWIP_TCP_PCB_NUM_EXT_ARGS -static void tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args); -#endif - -/** - * Initialize this module. - */ -void -tcp_init(void) -{ -#ifdef LWIP_RAND - tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); -#endif /* LWIP_RAND */ -} - -/** Free a tcp pcb */ -void -tcp_free(struct tcp_pcb *pcb) -{ - LWIP_ASSERT("tcp_free: LISTEN", pcb->state != LISTEN); -#if LWIP_TCP_PCB_NUM_EXT_ARGS - tcp_ext_arg_invoke_callbacks_destroyed(pcb->ext_args); -#endif - memp_free(MEMP_TCP_PCB, pcb); -} - -/** Free a tcp listen pcb */ -static void -tcp_free_listen(struct tcp_pcb *pcb) -{ - LWIP_ASSERT("tcp_free_listen: !LISTEN", pcb->state != LISTEN); -#if LWIP_TCP_PCB_NUM_EXT_ARGS - tcp_ext_arg_invoke_callbacks_destroyed(pcb->ext_args); -#endif - memp_free(MEMP_TCP_PCB_LISTEN, pcb); -} - -/** - * Called periodically to dispatch TCP timers. - */ -void -tcp_tmr(void) -{ - /* Call tcp_fasttmr() every 250 ms */ - tcp_fasttmr(); - - if (++tcp_timer & 1) { - /* Call tcp_slowtmr() every 500 ms, i.e., every other timer - tcp_tmr() is called. */ - tcp_slowtmr(); - } -} - -#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG -/** Called when a listen pcb is closed. Iterates one pcb list and removes the - * closed listener pcb from pcb->listener if matching. - */ -static void -tcp_remove_listener(struct tcp_pcb *list, struct tcp_pcb_listen *lpcb) -{ - struct tcp_pcb *pcb; - - LWIP_ASSERT("tcp_remove_listener: invalid listener", lpcb != NULL); - - for (pcb = list; pcb != NULL; pcb = pcb->next) { - if (pcb->listener == lpcb) { - pcb->listener = NULL; - } - } -} -#endif - -/** Called when a listen pcb is closed. Iterates all pcb lists and removes the - * closed listener pcb from pcb->listener if matching. - */ -static void -tcp_listen_closed(struct tcp_pcb *pcb) -{ -#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG - size_t i; - LWIP_ASSERT("pcb != NULL", pcb != NULL); - LWIP_ASSERT("pcb->state == LISTEN", pcb->state == LISTEN); - for (i = 1; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) { - tcp_remove_listener(*tcp_pcb_lists[i], (struct tcp_pcb_listen *)pcb); - } -#endif - LWIP_UNUSED_ARG(pcb); -} - -#if TCP_LISTEN_BACKLOG -/** @ingroup tcp_raw - * Delay accepting a connection in respect to the listen backlog: - * the number of outstanding connections is increased until - * tcp_backlog_accepted() is called. - * - * ATTENTION: the caller is responsible for calling tcp_backlog_accepted() - * or else the backlog feature will get out of sync! - * - * @param pcb the connection pcb which is not fully accepted yet - */ -void -tcp_backlog_delayed(struct tcp_pcb *pcb) -{ - LWIP_ASSERT("pcb != NULL", pcb != NULL); - LWIP_ASSERT_CORE_LOCKED(); - if ((pcb->flags & TF_BACKLOGPEND) == 0) { - if (pcb->listener != NULL) { - pcb->listener->accepts_pending++; - LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0); - tcp_set_flags(pcb, TF_BACKLOGPEND); - } - } -} - -/** @ingroup tcp_raw - * A delayed-accept a connection is accepted (or closed/aborted): decreases - * the number of outstanding connections after calling tcp_backlog_delayed(). - * - * ATTENTION: the caller is responsible for calling tcp_backlog_accepted() - * or else the backlog feature will get out of sync! - * - * @param pcb the connection pcb which is now fully accepted (or closed/aborted) - */ -void -tcp_backlog_accepted(struct tcp_pcb *pcb) -{ - LWIP_ASSERT("pcb != NULL", pcb != NULL); - LWIP_ASSERT_CORE_LOCKED(); - if ((pcb->flags & TF_BACKLOGPEND) != 0) { - if (pcb->listener != NULL) { - LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0); - pcb->listener->accepts_pending--; - tcp_clear_flags(pcb, TF_BACKLOGPEND); - } - } -} -#endif /* TCP_LISTEN_BACKLOG */ - -/** - * 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) -{ - LWIP_ASSERT("tcp_close_shutdown: invalid pcb", pcb != NULL); - - if (rst_on_unacked_data && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { - if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND_MAX(pcb))) { - /* 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, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port); - - tcp_pcb_purge(pcb); - TCP_RMV_ACTIVE(pcb); - /* Deallocate the pcb since we already sent a RST for it */ - if (tcp_input_pcb == pcb) { - /* prevent using a deallocated pcb: free it from tcp_input later */ - tcp_trigger_input_pcb_close(); - } else { - tcp_free(pcb); - } - return ERR_OK; - } - } - - /* - states which free the pcb are handled here, - - states which send FIN and change state are handled in tcp_close_shutdown_fin() */ - 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. */ - if (pcb->local_port != 0) { - TCP_RMV(&tcp_bound_pcbs, pcb); - } - tcp_free(pcb); - break; - case LISTEN: - tcp_listen_closed(pcb); - tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb); - tcp_free_listen(pcb); - break; - case SYN_SENT: - TCP_PCB_REMOVE_ACTIVE(pcb); - tcp_free(pcb); - MIB2_STATS_INC(mib2.tcpattemptfails); - break; - default: - return tcp_close_shutdown_fin(pcb); - } - return ERR_OK; -} - -static err_t -tcp_close_shutdown_fin(struct tcp_pcb *pcb) -{ - err_t err; - LWIP_ASSERT("pcb != NULL", pcb != NULL); - - switch (pcb->state) { - case SYN_RCVD: - err = tcp_send_fin(pcb); - if (err == ERR_OK) { - tcp_backlog_accepted(pcb); - MIB2_STATS_INC(mib2.tcpattemptfails); - pcb->state = FIN_WAIT_1; - } - break; - case ESTABLISHED: - err = tcp_send_fin(pcb); - if (err == ERR_OK) { - MIB2_STATS_INC(mib2.tcpestabresets); - pcb->state = FIN_WAIT_1; - } - break; - case CLOSE_WAIT: - err = tcp_send_fin(pcb); - if (err == ERR_OK) { - MIB2_STATS_INC(mib2.tcpestabresets); - pcb->state = LAST_ACK; - } - break; - default: - /* Has already been closed, do nothing. */ - return ERR_OK; - } - - if (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. */ - tcp_output(pcb); - } else if (err == ERR_MEM) { - /* Mark this pcb for closing. Closing is retried from tcp_tmr. */ - tcp_set_flags(pcb, TF_CLOSEPEND); - /* We have to return ERR_OK from here to indicate to the callers that this - pcb should not be used any more as it will be freed soon via tcp_tmr. - This is OK here since sending FIN does not guarantee a time frime for - actually freeing the pcb, either (it is left in closure states for - remote ACK or timeout) */ - return ERR_OK; - } - return err; -} - -/** - * @ingroup tcp_raw - * 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). - * - * The function may return ERR_MEM if no memory - * was available for closing the connection. If so, the application - * should wait and try again either by using the acknowledgment - * callback or the polling functionality. If the close succeeds, the - * function returns ERR_OK. - * - * @param pcb the tcp_pcb to close - * @return ERR_OK if connection has been closed - * another err_t if closing failed and pcb is not freed - */ -err_t -tcp_close(struct tcp_pcb *pcb) -{ - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("tcp_close: invalid pcb", pcb != NULL, return ERR_ARG); - LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); - - tcp_debug_print_state(pcb->state); - - if (pcb->state != LISTEN) { - /* Set a flag not to receive any more data... */ - tcp_set_flags(pcb, TF_RXCLOSED); - } - /* ... and close */ - return tcp_close_shutdown(pcb, 1); -} - -/** - * @ingroup tcp_raw - * Causes all or part of a full-duplex connection of this PCB to be shut down. - * This doesn't deallocate the PCB unless shutting down both sides! - * Shutting down both sides is the same as calling tcp_close, so if it succeds - * (i.e. returns ER_OK), the PCB must not be referenced any more! - * - * @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) -{ - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("tcp_shutdown: invalid pcb", pcb != NULL, return ERR_ARG); - - if (pcb->state == LISTEN) { - return ERR_CONN; - } - if (shut_rx) { - /* shut down the receive side: set a flag not to receive any more data... */ - tcp_set_flags(pcb, TF_RXCLOSED); - if (shut_tx) { - /* shutting down the tx AND rx side is the same as closing for the raw API */ - return tcp_close_shutdown(pcb, 1); - } - /* ... and free buffered data */ - if (pcb->refused_data != NULL) { - pbuf_free(pcb->refused_data); - pcb->refused_data = NULL; - } - } - 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, (u8_t)shut_rx); - default: - /* Not (yet?) connected, cannot shutdown the TX side as that would bring us - into CLOSED state, where the PCB is deallocated. */ - return ERR_CONN; - } - } - 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; -#if LWIP_CALLBACK_API - tcp_err_fn errf; -#endif /* LWIP_CALLBACK_API */ - void *errf_arg; - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("tcp_abandon: invalid pcb", pcb != NULL, return); - - /* 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); - tcp_free(pcb); - } else { - int send_rst = 0; - u16_t local_port = 0; - enum tcp_state last_state; - seqno = pcb->snd_nxt; - ackno = pcb->rcv_nxt; -#if LWIP_CALLBACK_API - errf = pcb->errf; -#endif /* LWIP_CALLBACK_API */ - errf_arg = pcb->callback_arg; - if (pcb->state == CLOSED) { - if (pcb->local_port != 0) { - /* bound, not yet opened */ - TCP_RMV(&tcp_bound_pcbs, pcb); - } - } else { - send_rst = reset; - local_port = pcb->local_port; - TCP_PCB_REMOVE_ACTIVE(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 */ - tcp_backlog_accepted(pcb); - if (send_rst) { - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); - tcp_rst(pcb, seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port); - } - last_state = pcb->state; - tcp_free(pcb); - TCP_EVENT_ERR(last_state, errf, errf_arg, ERR_ABRT); - } -} - -/** - * @ingroup tcp_raw - * 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); -} - -/** - * @ingroup tcp_raw - * Binds the connection to a local port number and IP address. If the - * IP address is not given (i.e., ipaddr == IP_ANY_TYPE), the connection is - * bound to all local IP addresses. - * If another connection is bound to the same port, the function will - * return ERR_USE, otherwise ERR_OK is returned. - * - * @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 IPx_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_VAL if bind failed because the PCB is not in a valid state - * ERR_OK if bound - */ -err_t -tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) -{ - int i; - int max_pcb_list = NUM_TCP_PCB_LISTS; - struct tcp_pcb *cpcb; -#if LWIP_IPV6 && LWIP_IPV6_SCOPES - ip_addr_t zoned_ipaddr; -#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ - - LWIP_ASSERT_CORE_LOCKED(); - -#if LWIP_IPV4 - /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ - if (ipaddr == NULL) { - ipaddr = IP4_ADDR_ANY; - } -#else /* LWIP_IPV4 */ - LWIP_ERROR("tcp_bind: invalid ipaddr", ipaddr != NULL, return ERR_ARG); -#endif /* LWIP_IPV4 */ - - LWIP_ERROR("tcp_bind: invalid pcb", pcb != NULL, return ERR_ARG); - - LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL); - -#if SO_REUSE - /* Unless the REUSEADDR flag is set, - we have to check the pcbs in TIME-WAIT state, also. - We do not dump TIME_WAIT pcb's; they can still be matched by incoming - packets using both local and remote IP addresses and ports to distinguish. - */ - if (ip_get_option(pcb, SOF_REUSEADDR)) { - max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT; - } -#endif /* SO_REUSE */ - -#if LWIP_IPV6 && LWIP_IPV6_SCOPES - /* If the given IP address should have a zone but doesn't, assign one now. - * This is legacy support: scope-aware callers should always provide properly - * zoned source addresses. Do the zone selection before the address-in-use - * check below; as such we have to make a temporary copy of the address. */ - if (IP_IS_V6(ipaddr) && ip6_addr_lacks_zone(ip_2_ip6(ipaddr), IP6_UNICAST)) { - ip_addr_copy(zoned_ipaddr, *ipaddr); - ip6_addr_select_zone(ip_2_ip6(&zoned_ipaddr), ip_2_ip6(&zoned_ipaddr)); - ipaddr = &zoned_ipaddr; - } -#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ - - if (port == 0) { - port = tcp_new_port(); - if (port == 0) { - return ERR_BUF; - } - } else { - /* 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 (!ip_get_option(pcb, SOF_REUSEADDR) || - !ip_get_option(cpcb, SOF_REUSEADDR)) -#endif /* SO_REUSE */ - { - /* @todo: check accept_any_ip_version */ - if ((IP_IS_V6(ipaddr) == IP_IS_V6_VAL(cpcb->local_ip)) && - (ip_addr_isany(&cpcb->local_ip) || - ip_addr_isany(ipaddr) || - ip_addr_cmp(&cpcb->local_ip, ipaddr))) { - return ERR_USE; - } - } - } - } - } - } - - if (!ip_addr_isany(ipaddr) -#if LWIP_IPV4 && LWIP_IPV6 - || (IP_GET_TYPE(ipaddr) != IP_GET_TYPE(&pcb->local_ip)) -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - ) { - ip_addr_set(&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; -} - -/** - * @ingroup tcp_raw - * Binds the connection to a netif and IP address. - * After calling this function, all packets received via this PCB - * are guaranteed to have come in via the specified netif, and all - * outgoing packets will go out via the specified netif. - * - * @param pcb the tcp_pcb to bind. - * @param netif the netif to bind to. Can be NULL. - */ -void -tcp_bind_netif(struct tcp_pcb *pcb, const struct netif *netif) -{ - LWIP_ASSERT_CORE_LOCKED(); - if (netif != NULL) { - pcb->netif_idx = netif_get_index(netif); - } else { - pcb->netif_idx = NETIF_NO_INDEX; - } -} - -#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(err); - - LWIP_ASSERT("tcp_accept_null: invalid pcb", pcb != NULL); - - tcp_abort(pcb); - - return ERR_ABRT; -} -#endif /* LWIP_CALLBACK_API */ - -/** - * @ingroup tcp_raw - * 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. - * When an incoming connection is accepted, the function specified with - * the tcp_accept() function will be called. The pcb has to be bound - * to a local port with the tcp_bind() function. - * - * The tcp_listen() function returns a new connection identifier, and - * the one passed as an argument to the function will be - * deallocated. The reason for this behavior is that less memory is - * needed for a connection that is listening, so tcp_listen() will - * reclaim the memory needed for the original connection and allocate a - * new smaller memory block for the listening connection. - * - * tcp_listen() may return NULL if no memory was available for the - * listening connection. If so, the memory associated with the pcb - * passed as an argument to tcp_listen() will not be deallocated. - * - * The backlog limits the number of outstanding connections - * in the listen queue to the value specified by the backlog argument. - * To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h. - * - * @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_with_backlog(tpcb, backlog); - */ -struct tcp_pcb * -tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) -{ - LWIP_ASSERT_CORE_LOCKED(); - return tcp_listen_with_backlog_and_err(pcb, backlog, NULL); -} - -/** - * @ingroup tcp_raw - * 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. - * - * @param pcb the original tcp_pcb - * @param backlog the incoming connections queue limit - * @param err when NULL is returned, this contains the error reason - * @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_with_backlog_and_err(tpcb, backlog, &err); - */ -struct tcp_pcb * -tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) -{ - struct tcp_pcb_listen *lpcb = NULL; - err_t res; - - LWIP_UNUSED_ARG(backlog); - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("tcp_listen_with_backlog_and_err: invalid pcb", pcb != NULL, res = ERR_ARG; goto done); - LWIP_ERROR("tcp_listen_with_backlog_and_err: pcb already connected", pcb->state == CLOSED, res = ERR_CLSD; goto done); - - /* already listening? */ - if (pcb->state == LISTEN) { - lpcb = (struct tcp_pcb_listen *)pcb; - res = ERR_ALREADY; - goto done; - } -#if SO_REUSE - if (ip_get_option(pcb, SOF_REUSEADDR)) { - /* 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) && - ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { - /* this address/port is already used */ - lpcb = NULL; - res = ERR_USE; - goto done; - } - } - } -#endif /* SO_REUSE */ - lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN); - if (lpcb == NULL) { - res = ERR_MEM; - goto done; - } - 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->netif_idx = NETIF_NO_INDEX; - lpcb->ttl = pcb->ttl; - lpcb->tos = pcb->tos; -#if LWIP_IPV4 && LWIP_IPV6 - IP_SET_TYPE_VAL(lpcb->remote_ip, pcb->local_ip.type); -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - ip_addr_copy(lpcb->local_ip, pcb->local_ip); - if (pcb->local_port != 0) { - TCP_RMV(&tcp_bound_pcbs, pcb); - } -#if LWIP_TCP_PCB_NUM_EXT_ARGS - /* copy over ext_args to listening pcb */ - memcpy(&lpcb->ext_args, &pcb->ext_args, sizeof(pcb->ext_args)); -#endif - tcp_free(pcb); -#if LWIP_CALLBACK_API - lpcb->accept = tcp_accept_null; -#endif /* LWIP_CALLBACK_API */ -#if TCP_LISTEN_BACKLOG - lpcb->accepts_pending = 0; - tcp_backlog_set(lpcb, backlog); -#endif /* TCP_LISTEN_BACKLOG */ - TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb); - res = ERR_OK; -done: - if (err != NULL) { - *err = res; - } - 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; - - LWIP_ASSERT("tcp_update_rcv_ann_wnd: invalid pcb", pcb != NULL); - 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; -#if !LWIP_WND_SCALE - LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff); -#endif - pcb->rcv_ann_wnd = (tcpwnd_size_t)new_rcv_ann_wnd; - } - return 0; - } -} - -/** - * @ingroup tcp_raw - * 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) -{ - u32_t wnd_inflation; - tcpwnd_size_t rcv_wnd; - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("tcp_recved: invalid pcb", pcb != NULL, return); - - /* pcb->state LISTEN not allowed here */ - LWIP_ASSERT("don't call tcp_recved for listen-pcbs", - pcb->state != LISTEN); - - rcv_wnd = (tcpwnd_size_t)(pcb->rcv_wnd + len); - if ((rcv_wnd > TCP_WND_MAX(pcb)) || (rcv_wnd < pcb->rcv_wnd)) { - /* window got too big or tcpwnd_size_t overflow */ - LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: window got too big or tcpwnd_size_t overflow\n")); - pcb->rcv_wnd = TCP_WND_MAX(pcb); - } else { - pcb->rcv_wnd = rcv_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: received %"U16_F" bytes, wnd %"TCPWNDSIZE_F" (%"TCPWNDSIZE_F").\n", - len, pcb->rcv_wnd, (u16_t)(TCP_WND_MAX(pcb) - pcb->rcv_wnd))); -} - -/** - * Allocate a new local TCP port. - * - * @return a new (free) local TCP port number - */ -static u16_t -tcp_new_port(void) -{ - u8_t i; - u16_t n = 0; - struct tcp_pcb *pcb; - -again: - tcp_port++; - if (tcp_port == TCP_LOCAL_PORT_RANGE_END) { - tcp_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 == tcp_port) { - n++; - if (n > (TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START)) { - return 0; - } - goto again; - } - } - } - return tcp_port; -} - -/** - * @ingroup tcp_raw - * Connects to another host. The function given as the "connected" - * argument will be called when the connection has been established. - * Sets up the pcb to connect to the remote host and sends the - * initial SYN segment which opens the connection. - * - * The tcp_connect() function returns immediately; it does not wait for - * the connection to be properly setup. Instead, it will call the - * function specified as the fourth argument (the "connected" argument) - * when the connection is established. If the connection could not be - * properly established, either because the other host refused the - * connection or because the other host didn't answer, the "err" - * callback function of this pcb (registered with tcp_err, see below) - * will be called. - * - * The tcp_connect() function can return ERR_MEM if no memory is - * available for enqueueing the SYN segment. If the SYN indeed was - * enqueued successfully, the tcp_connect() function returns ERR_OK. - * - * @param pcb the tcp_pcb used to establish the connection - * @param ipaddr the remote ip address to connect to - * @param port the remote tcp port to connect to - * @param connected callback function to call when connected (on error, - the err calback will be called) - * @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, const ip_addr_t *ipaddr, u16_t port, - tcp_connected_fn connected) -{ - struct netif *netif = NULL; - err_t ret; - u32_t iss; - u16_t old_local_port; - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("tcp_connect: invalid pcb", pcb != NULL, return ERR_ARG); - LWIP_ERROR("tcp_connect: invalid ipaddr", ipaddr != NULL, return ERR_ARG); - - LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); - ip_addr_set(&pcb->remote_ip, ipaddr); - pcb->remote_port = port; - - if (pcb->netif_idx != NETIF_NO_INDEX) { - netif = netif_get_by_index(pcb->netif_idx); - } else { - /* check if we have a route to the remote host */ - netif = ip_route(&pcb->local_ip, &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; - } - - /* check if local IP has been assigned to pcb, if not, get one */ - if (ip_addr_isany(&pcb->local_ip)) { - const ip_addr_t *local_ip = ip_netif_get_local_ip(netif, ipaddr); - if (local_ip == NULL) { - return ERR_RTE; - } - ip_addr_copy(pcb->local_ip, *local_ip); - } - -#if LWIP_IPV6 && LWIP_IPV6_SCOPES - /* If the given IP address should have a zone but doesn't, assign one now. - * Given that we already have the target netif, this is easy and cheap. */ - if (IP_IS_V6(&pcb->remote_ip) && - ip6_addr_lacks_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNICAST)) { - ip6_addr_assign_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNICAST, netif); - } -#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ - - old_local_port = pcb->local_port; - if (pcb->local_port == 0) { - pcb->local_port = tcp_new_port(); - if (pcb->local_port == 0) { - return ERR_BUF; - } - } else { -#if SO_REUSE - if (ip_get_option(pcb, SOF_REUSEADDR)) { - /* 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); - pcb->rcv_nxt = 0; - pcb->snd_nxt = iss; - pcb->lastack = iss - 1; - pcb->snd_wl2 = iss - 1; - pcb->snd_lbb = iss - 1; - /* Start with a window that does not need scaling. When window scaling is - enabled and used, the window is enlarged when both sides agree on scaling. */ - pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(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 = INITIAL_MSS; -#if TCP_CALCULATE_EFF_SEND_MSS - pcb->mss = tcp_eff_send_mss_netif(pcb->mss, netif, &pcb->remote_ip); -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - pcb->cwnd = 1; -#if LWIP_CALLBACK_API - pcb->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 */ - pcb->state = SYN_SENT; - if (old_local_port != 0) { - TCP_RMV(&tcp_bound_pcbs, pcb); - } - TCP_REG_ACTIVE(pcb); - MIB2_STATS_INC(mib2.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; - tcpwnd_size_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; - ++tcp_timer_ctr; - -tcp_slowtmr_start: - /* 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); - if (pcb->last_timer == tcp_timer_ctr) { - /* skip this pcb, we have already processed it */ - prev = pcb; - pcb = pcb->next; - continue; - } - pcb->last_timer = tcp_timer_ctr; - - 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) { - LWIP_ASSERT("tcp_slowtimr: persist ticking with in-flight data", pcb->unacked == NULL); - LWIP_ASSERT("tcp_slowtimr: persist ticking with empty send buffer", pcb->unsent != NULL); - if (pcb->persist_probe >= TCP_MAXRTX) { - ++pcb_remove; /* max probes reached */ - } else { - u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff - 1]; - if (pcb->persist_cnt < backoff_cnt) { - pcb->persist_cnt++; - } - if (pcb->persist_cnt >= backoff_cnt) { - int next_slot = 1; /* increment timer to next slot */ - /* If snd_wnd is zero, send 1 byte probes */ - if (pcb->snd_wnd == 0) { - if (tcp_zero_window_probe(pcb) != ERR_OK) { - next_slot = 0; /* try probe again with current slot */ - } - /* snd_wnd not fully closed, split unsent head and fill window */ - } else { - if (tcp_split_unsent_seg(pcb, (u16_t)pcb->snd_wnd) == ERR_OK) { - if (tcp_output(pcb) == ERR_OK) { - /* sending will cancel persist timer, else retry with current slot */ - next_slot = 0; - } - } - } - if (next_slot) { - pcb->persist_cnt = 0; - if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) { - pcb->persist_backoff++; - } - } - } - } - } else { - /* Increase the retransmission timer if it is running */ - if ((pcb->rtime >= 0) && (pcb->rtime < 0x7FFF)) { - ++pcb->rtime; - } - - if (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)); - /* If prepare phase fails but we have unsent data but no unacked data, - still execute the backoff calculations below, as this means we somehow - failed to send segment. */ - if ((tcp_rexmit_rto_prepare(pcb) == ERR_OK) || ((pcb->unacked == NULL) && (pcb->unsent != NULL))) { - /* Double retransmission time-out unless we are trying to - * connect to somebody (i.e., we are in SYN_SENT). */ - if (pcb->state != SYN_SENT) { - u8_t backoff_idx = LWIP_MIN(pcb->nrtx, sizeof(tcp_backoff) - 1); - int calc_rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[backoff_idx]; - pcb->rto = (s16_t)LWIP_MIN(calc_rto, 0x7FFF); - } - - /* 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 < (tcpwnd_size_t)(pcb->mss << 1)) { - pcb->ssthresh = (tcpwnd_size_t)(pcb->mss << 1); - } - pcb->cwnd = pcb->mss; - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"TCPWNDSIZE_F - " ssthresh %"TCPWNDSIZE_F"\n", - pcb->cwnd, pcb->ssthresh)); - pcb->bytes_acked = 0; - - /* The following needs to be called AFTER cwnd is set to one - mss - STJ */ - tcp_rexmit_rto_commit(pcb); - } - } - } - } - /* Check if this PCB has stayed too long in FIN-WAIT-2 */ - if (pcb->state == FIN_WAIT_2) { - /* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */ - if (pcb->flags & TF_RXCLOSED) { - /* PCB was fully closed (either through close() or SHUT_RDWR): - normal FIN-WAIT timeout handling. */ - 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 (ip_get_option(pcb, SOF_KEEPALIVE) && - ((pcb->state == ESTABLISHED) || - (pcb->state == CLOSE_WAIT))) { - if ((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + TCP_KEEP_DUR(pcb)) / TCP_SLOW_INTERVAL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to ")); - ip_addr_debug_print_val(TCP_DEBUG, pcb->remote_ip); - LWIP_DEBUGF(TCP_DEBUG, ("\n")); - - ++pcb_remove; - ++pcb_reset; - } else if ((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEP_INTVL(pcb)) - / TCP_SLOW_INTERVAL) { - err = tcp_keepalive(pcb); - if (err == ERR_OK) { - 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 && - (tcp_ticks - pcb->tmr >= (u32_t)pcb->rto * TCP_OOSEQ_TIMEOUT)) { - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); - tcp_free_ooseq(pcb); - } -#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; -#if LWIP_CALLBACK_API - tcp_err_fn err_fn = pcb->errf; -#endif /* LWIP_CALLBACK_API */ - void *err_arg; - enum tcp_state last_state; - 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, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port); - } - - err_arg = pcb->callback_arg; - last_state = pcb->state; - pcb2 = pcb; - pcb = pcb->next; - tcp_free(pcb2); - - tcp_active_pcbs_changed = 0; - TCP_EVENT_ERR(last_state, err_fn, err_arg, ERR_ABRT); - if (tcp_active_pcbs_changed) { - goto tcp_slowtmr_start; - } - } 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_active_pcbs_changed = 0; - TCP_EVENT_POLL(prev, err); - if (tcp_active_pcbs_changed) { - goto tcp_slowtmr_start; - } - /* 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; - tcp_free(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 or pending FINs. - * - * Automatically called from tcp_tmr(). - */ -void -tcp_fasttmr(void) -{ - struct tcp_pcb *pcb; - - ++tcp_timer_ctr; - -tcp_fasttmr_start: - pcb = tcp_active_pcbs; - - while (pcb != NULL) { - if (pcb->last_timer != tcp_timer_ctr) { - struct tcp_pcb *next; - pcb->last_timer = tcp_timer_ctr; - /* send delayed ACKs */ - if (pcb->flags & TF_ACK_DELAY) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); - tcp_ack_now(pcb); - tcp_output(pcb); - tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); - } - /* send pending FIN */ - if (pcb->flags & TF_CLOSEPEND) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: pending FIN\n")); - tcp_clear_flags(pcb, TF_CLOSEPEND); - tcp_close_shutdown_fin(pcb); - } - - next = pcb->next; - - /* If there is data which was previously "refused" by upper layer */ - if (pcb->refused_data != NULL) { - tcp_active_pcbs_changed = 0; - tcp_process_refused_data(pcb); - if (tcp_active_pcbs_changed) { - /* application callback has changed the pcb list: restart the loop */ - goto tcp_fasttmr_start; - } - } - pcb = next; - } else { - pcb = pcb->next; - } - } -} - -/** Call tcp_output for all active pcbs that have TF_NAGLEMEMERR set */ -void -tcp_txnow(void) -{ - struct tcp_pcb *pcb; - - for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - if (pcb->flags & TF_NAGLEMEMERR) { - tcp_output(pcb); - } - } -} - -/** Pass pcb->refused_data to the recv callback */ -err_t -tcp_process_refused_data(struct tcp_pcb *pcb) -{ -#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE - struct pbuf *rest; -#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - - LWIP_ERROR("tcp_process_refused_data: invalid pcb", pcb != NULL, return ERR_ARG); - -#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE - while (pcb->refused_data != NULL) -#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - { - err_t err; - u8_t refused_flags = pcb->refused_data->flags; - /* set pcb->refused_data to NULL in case the callback frees it and then - closes the pcb */ - struct pbuf *refused_data = pcb->refused_data; -#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE - pbuf_split_64k(refused_data, &rest); - pcb->refused_data = rest; -#else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - pcb->refused_data = NULL; -#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - /* Notify again application with data previously received. */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); - TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err); - if (err == ERR_OK) { - /* did refused_data include a FIN? */ - if ((refused_flags & PBUF_FLAG_TCP_FIN) -#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE - && (rest == NULL) -#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - ) { - /* correct rcv_wnd as the application won't call tcp_recved() - for the FIN's seqno */ - if (pcb->rcv_wnd != TCP_WND_MAX(pcb)) { - pcb->rcv_wnd++; - } - TCP_EVENT_CLOSED(pcb, err); - if (err == ERR_ABRT) { - return ERR_ABRT; - } - } - } else if (err == ERR_ABRT) { - /* 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")); - return ERR_ABRT; - } else { - /* data is still refused, pbuf is still valid (go on for ACK-only packets) */ -#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE - if (rest != NULL) { - pbuf_cat(refused_data, rest); - } -#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - pcb->refused_data = refused_data; - return ERR_INPROGRESS; - } - } - return ERR_OK; -} - -/** - * 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); - } -} - -/** - * @ingroup tcp - * 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) -{ - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("tcp_setprio: invalid pcb", pcb != NULL, return); - - 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; - - LWIP_ASSERT("tcp_seg_copy: invalid seg", seg != NULL); - - 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); - - LWIP_ERROR("tcp_recv_null: invalid pcb", pcb != NULL, return ERR_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 a lower priority than 'prio'. - * - * @param prio minimum priority - */ -static void -tcp_kill_prio(u8_t prio) -{ - struct tcp_pcb *pcb, *inactive; - u32_t inactivity; - u8_t mprio; - - mprio = LWIP_MIN(TCP_PRIO_MAX, prio); - - /* We want to kill connections with a lower prio, so bail out if - * supplied prio is 0 - there can never be a lower prio - */ - if (mprio == 0) { - return; - } - - /* We only want kill connections with a lower prio, so decrement prio by one - * and start searching for oldest connection with same or lower priority than mprio. - * We want to find the connections with the lowest possible prio, and among - * these the one with the longest inactivity time. - */ - mprio--; - - inactivity = 0; - inactive = NULL; - for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - /* lower prio is always a kill candidate */ - if ((pcb->prio < mprio) || - /* longer inactivity is also a kill candidate */ - ((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 specific state. - * Called from tcp_alloc() for LAST_ACK and CLOSING if no more connections are available. - */ -static void -tcp_kill_state(enum tcp_state state) -{ - struct tcp_pcb *pcb, *inactive; - u32_t inactivity; - - LWIP_ASSERT("invalid state", (state == CLOSING) || (state == LAST_ACK)); - - inactivity = 0; - inactive = NULL; - /* Go through the list of active pcbs and get the oldest pcb that is in state - CLOSING/LAST_ACK. */ - for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - if (pcb->state == state) { - if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { - inactivity = tcp_ticks - pcb->tmr; - inactive = pcb; - } - } - } - if (inactive != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_closing: killing oldest %s PCB %p (%"S32_F")\n", - tcp_state_str[state], (void *)inactive, inactivity)); - /* Don't send a RST, since no data is lost. */ - tcp_abandon(inactive, 0); - } -} - -/** - * Kills the oldest connection that is in TIME_WAIT state. - * Called from tcp_alloc() if no more connections are available. - */ -static void -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); - } -} - -/* Called when allocating a pcb fails. - * In this case, we want to handle all pcbs that want to close first: if we can - * now send the FIN (which failed before), the pcb might be in a state that is - * OK for us to now free it. - */ -static void -tcp_handle_closepend(void) -{ - struct tcp_pcb *pcb = tcp_active_pcbs; - - while (pcb != NULL) { - struct tcp_pcb *next = pcb->next; - /* send pending FIN */ - if (pcb->flags & TF_CLOSEPEND) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_handle_closepend: pending FIN\n")); - tcp_clear_flags(pcb, TF_CLOSEPEND); - tcp_close_shutdown_fin(pcb); - } - pcb = next; - } -} - -/** - * Allocate a new tcp_pcb structure. - * - * @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; - - LWIP_ASSERT_CORE_LOCKED(); - - pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); - if (pcb == NULL) { - /* Try to send FIN for all pcbs stuck in TF_CLOSEPEND first */ - tcp_handle_closepend(); - - /* 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 oldest connection in LAST-ACK (these wouldn't go to TIME-WAIT). */ - LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest LAST-ACK connection\n")); - tcp_kill_state(LAST_ACK); - /* Try to allocate a tcp_pcb again. */ - pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); - if (pcb == NULL) { - /* Try killing oldest connection in CLOSING. */ - LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest CLOSING connection\n")); - tcp_kill_state(CLOSING); - /* Try to allocate a tcp_pcb again. */ - pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); - if (pcb == NULL) { - /* Try killing oldest active connection with lower priority than the new one. */ - LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing oldest 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 multiple times before */ - MEMP_STATS_DEC(err, MEMP_TCP_PCB); - } - } - if (pcb != NULL) { - /* adjust err stats: memp_malloc failed multiple times before */ - MEMP_STATS_DEC(err, MEMP_TCP_PCB); - } - } - if (pcb != NULL) { - /* adjust err stats: memp_malloc failed multiple times before */ - MEMP_STATS_DEC(err, MEMP_TCP_PCB); - } - } - if (pcb != NULL) { - /* adjust err stats: memp_malloc failed above */ - MEMP_STATS_DEC(err, MEMP_TCP_PCB); - } - } - if (pcb != NULL) { - /* zero out the whole pcb, so there is no need to initialize members to zero */ - memset(pcb, 0, sizeof(struct tcp_pcb)); - pcb->prio = prio; - pcb->snd_buf = TCP_SND_BUF; - /* Start with a window that does not need scaling. When window scaling is - enabled and used, the window is enlarged when both sides agree on scaling. */ - pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND); - pcb->ttl = TCP_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 = INITIAL_MSS; - pcb->rto = 3000 / TCP_SLOW_INTERVAL; - pcb->sv = 3000 / TCP_SLOW_INTERVAL; - pcb->rtime = -1; - pcb->cwnd = 1; - pcb->tmr = tcp_ticks; - pcb->last_timer = tcp_timer_ctr; - - /* RFC 5681 recommends setting ssthresh abritrarily high and gives an example - of using the largest advertised receive window. We've seen complications with - receiving TCPs that use window scaling and/or window auto-tuning where the - initial advertised window is very small and then grows rapidly once the - connection is established. To avoid these complications, we set ssthresh to the - largest effective cwnd (amount of in-flight data) that the sender can have. */ - pcb->ssthresh = TCP_SND_BUF; - -#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 */ - } - return pcb; -} - -/** - * @ingroup tcp_raw - * 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(). - * If memory is not available for creating the new pcb, NULL is returned. - * - * @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); -} - -/** - * @ingroup tcp_raw - * 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(). - * - * @param type IP address type, see @ref lwip_ip_addr_type definitions. - * If you want to listen to IPv4 and IPv6 (dual-stack) connections, - * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. - * @return a new tcp_pcb that initially is in state CLOSED - */ -struct tcp_pcb * -tcp_new_ip_type(u8_t type) -{ - struct tcp_pcb *pcb; - pcb = tcp_alloc(TCP_PRIO_NORMAL); -#if LWIP_IPV4 && LWIP_IPV6 - if (pcb != NULL) { - IP_SET_TYPE_VAL(pcb->local_ip, type); - IP_SET_TYPE_VAL(pcb->remote_ip, type); - } -#else - LWIP_UNUSED_ARG(type); -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - return pcb; -} - -/** - * @ingroup tcp_raw - * Specifies the program specific state that should be passed to all - * other callback functions. The "pcb" argument is the current TCP - * connection control block, and the "arg" argument is the argument - * that will be passed to the callbacks. - * - * @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) -{ - LWIP_ASSERT_CORE_LOCKED(); - /* This function is allowed to be called for both listen pcbs and - connection pcbs. */ - if (pcb != NULL) { - pcb->callback_arg = arg; - } -} -#if LWIP_CALLBACK_API - -/** - * @ingroup tcp_raw - * Sets the callback function that will be called when new data - * arrives. The callback function will be passed a NULL pbuf to - * indicate that the remote host has closed the connection. If the - * callback function returns ERR_OK or ERR_ABRT it must have - * freed the pbuf, otherwise it must not have freed it. - * - * @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) -{ - LWIP_ASSERT_CORE_LOCKED(); - if (pcb != NULL) { - LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN); - pcb->recv = recv; - } -} - -/** - * @ingroup tcp_raw - * Specifies the callback function that should be called when data has - * successfully been received (i.e., acknowledged) by the remote - * host. The len argument passed to the callback function gives the - * amount bytes that was acknowledged by the last acknowledgment. - * - * @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) -{ - LWIP_ASSERT_CORE_LOCKED(); - if (pcb != NULL) { - LWIP_ASSERT("invalid socket state for sent callback", pcb->state != LISTEN); - pcb->sent = sent; - } -} - -/** - * @ingroup tcp_raw - * Used to specify the function that should be called when a fatal error - * has occurred on the connection. - * - * If a connection is aborted because of an error, the application is - * alerted of this event by the err callback. Errors that might abort a - * connection are when there is a shortage of memory. The callback - * function to be called is set using the tcp_err() function. - * - * @note The corresponding pcb is already freed when this callback is called! - * - * @param pcb tcp_pcb to set the err callback - * @param err callback function to call for this pcb when a fatal error - * has occurred on the connection - */ -void -tcp_err(struct tcp_pcb *pcb, tcp_err_fn err) -{ - LWIP_ASSERT_CORE_LOCKED(); - if (pcb != NULL) { - LWIP_ASSERT("invalid socket state for err callback", pcb->state != LISTEN); - pcb->errf = err; - } -} - -/** - * @ingroup tcp_raw - * Used for specifying the function that should be called when a - * LISTENing connection has been connected to another host. - * - * @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) -{ - LWIP_ASSERT_CORE_LOCKED(); - if ((pcb != NULL) && (pcb->state == LISTEN)) { - struct tcp_pcb_listen *lpcb = (struct tcp_pcb_listen *)pcb; - lpcb->accept = accept; - } -} -#endif /* LWIP_CALLBACK_API */ - - -/** - * @ingroup tcp_raw - * Specifies the polling interval and the callback function that should - * be called to poll the application. The interval is specified in - * number of TCP coarse grained timer shots, which typically occurs - * twice a second. An interval of 10 means that the application would - * be polled every 5 seconds. - * - * When a connection is idle (i.e., no data is either transmitted or - * received), lwIP will repeatedly poll the application by calling a - * specified callback function. This can be used either as a watchdog - * timer for killing connections that have stayed idle for too long, or - * as a method of waiting for memory to become available. For instance, - * if a call to tcp_write() has failed because memory wasn't available, - * the application may use the polling functionality to call tcp_write() - * again when the connection has been idle for a while. - */ -void -tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) -{ - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("tcp_poll: invalid pcb", pcb != NULL, return); - LWIP_ASSERT("invalid socket state for poll", pcb->state != LISTEN); - -#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) -{ - LWIP_ERROR("tcp_pcb_purge: invalid pcb", pcb != NULL, return); - - if (pcb->state != CLOSED && - pcb->state != TIME_WAIT && - pcb->state != LISTEN) { - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); - - tcp_backlog_accepted(pcb); - - 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_free_ooseq(pcb); - } -#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) -{ - LWIP_ASSERT("tcp_pcb_remove: invalid pcb", pcb != NULL); - LWIP_ASSERT("tcp_pcb_remove: invalid pcblist", pcblist != NULL); - - 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)) { - tcp_ack_now(pcb); - 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; - /* reset the local port to prevent the pcb from being 'bound' */ - pcb->local_port = 0; - - 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(struct tcp_pcb *pcb) -{ -#ifdef LWIP_HOOK_TCP_ISN - LWIP_ASSERT("tcp_next_iss: invalid pcb", pcb != NULL); - return LWIP_HOOK_TCP_ISN(&pcb->local_ip, pcb->local_port, &pcb->remote_ip, pcb->remote_port); -#else /* LWIP_HOOK_TCP_ISN */ - static u32_t iss = 6510; - - LWIP_ASSERT("tcp_next_iss: invalid pcb", pcb != NULL); - LWIP_UNUSED_ARG(pcb); - - iss += tcp_ticks; /* XXX */ - return iss; -#endif /* LWIP_HOOK_TCP_ISN */ -} - -#if TCP_CALCULATE_EFF_SEND_MSS -/** - * Calculates the effective send mss that can be used for a specific IP address - * by calculating the minimum of TCP_MSS and the mtu (if set) of the target - * netif (if not NULL). - */ -u16_t -tcp_eff_send_mss_netif(u16_t sendmss, struct netif *outif, const ip_addr_t *dest) -{ - u16_t mss_s; - u16_t mtu; - - LWIP_UNUSED_ARG(dest); /* in case IPv6 is disabled */ - - LWIP_ASSERT("tcp_eff_send_mss_netif: invalid dst_ip", dest != NULL); - -#if LWIP_IPV6 -#if LWIP_IPV4 - if (IP_IS_V6(dest)) -#endif /* LWIP_IPV4 */ - { - /* First look in destination cache, to see if there is a Path MTU. */ - mtu = nd6_get_destination_mtu(ip_2_ip6(dest), outif); - } -#if LWIP_IPV4 - else -#endif /* LWIP_IPV4 */ -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 - { - if (outif == NULL) { - return sendmss; - } - mtu = outif->mtu; - } -#endif /* LWIP_IPV4 */ - - if (mtu != 0) { - u16_t offset; -#if LWIP_IPV6 -#if LWIP_IPV4 - if (IP_IS_V6(dest)) -#endif /* LWIP_IPV4 */ - { - offset = IP6_HLEN + TCP_HLEN; - } -#if LWIP_IPV4 - else -#endif /* LWIP_IPV4 */ -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 - { - offset = IP_HLEN + TCP_HLEN; - } -#endif /* LWIP_IPV4 */ - mss_s = (mtu > offset) ? (u16_t)(mtu - offset) : 0; - /* 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 */ - -/** Helper function for tcp_netif_ip_addr_changed() that iterates a pcb list */ -static void -tcp_netif_ip_addr_changed_pcblist(const ip_addr_t *old_addr, struct tcp_pcb *pcb_list) -{ - struct tcp_pcb *pcb; - pcb = pcb_list; - - LWIP_ASSERT("tcp_netif_ip_addr_changed_pcblist: invalid old_addr", old_addr != NULL); - - while (pcb != NULL) { - /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&pcb->local_ip, old_addr) -#if LWIP_AUTOIP - /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ - && (!IP_IS_V4_VAL(pcb->local_ip) || !ip4_addr_islinklocal(ip_2_ip4(&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; - } - } -} - -/** This function is called from netif.c when address is changed or netif is removed - * - * @param old_addr IP address of the netif before change - * @param new_addr IP address of the netif after change or NULL if netif has been removed - */ -void -tcp_netif_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) -{ - struct tcp_pcb_listen *lpcb; - - if (!ip_addr_isany(old_addr)) { - tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_active_pcbs); - tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_bound_pcbs); - - if (!ip_addr_isany(new_addr)) { - /* PCB bound to current local interface address? */ - for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { - /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&lpcb->local_ip, old_addr)) { - /* The PCB is listening to the old ipaddr and - * is set to listen to the new one instead */ - ip_addr_copy(lpcb->local_ip, *new_addr); - } - } - } - } -} - -const char * -tcp_debug_state_str(enum tcp_state s) -{ - return tcp_state_str[s]; -} - -err_t -tcp_tcp_get_tcp_addrinfo(struct tcp_pcb *pcb, int local, ip_addr_t *addr, u16_t *port) -{ - if (pcb) { - if (local) { - if (addr) { - *addr = pcb->local_ip; - } - if (port) { - *port = pcb->local_port; - } - } else { - if (addr) { - *addr = pcb->remote_ip; - } - if (port) { - *port = pcb->remote_port; - } - } - return ERR_OK; - } - return ERR_VAL; -} - -#if TCP_QUEUE_OOSEQ -/* Free all ooseq pbufs (and possibly reset SACK state) */ -void -tcp_free_ooseq(struct tcp_pcb *pcb) -{ - if (pcb->ooseq) { - tcp_segs_free(pcb->ooseq); - pcb->ooseq = NULL; -#if LWIP_TCP_SACK_OUT - memset(pcb->rcv_sacks, 0, sizeof(pcb->rcv_sacks)); -#endif /* LWIP_TCP_SACK_OUT */ - } -} -#endif /* TCP_QUEUE_OOSEQ */ - -#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", - lwip_ntohs(tcphdr->src), lwip_ntohs(tcphdr->dest))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n", - lwip_ntohl(tcphdr->seqno))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n", - lwip_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), - (u16_t)(TCPH_FLAGS(tcphdr) >> 5 & 1), - (u16_t)(TCPH_FLAGS(tcphdr) >> 4 & 1), - (u16_t)(TCPH_FLAGS(tcphdr) >> 3 & 1), - (u16_t)(TCPH_FLAGS(tcphdr) >> 2 & 1), - (u16_t)(TCPH_FLAGS(tcphdr) >> 1 & 1), - (u16_t)(TCPH_FLAGS(tcphdr) & 1), - lwip_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", - lwip_ntohs(tcphdr->chksum), lwip_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; - struct tcp_pcb_listen *pcbl; - - 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 (pcbl = tcp_listen_pcbs.listen_pcbs; pcbl != NULL; pcbl = pcbl->next) { - LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F" ", pcbl->local_port)); - tcp_debug_print_state(pcbl->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 */ - -#if LWIP_TCP_PCB_NUM_EXT_ARGS -/** - * @defgroup tcp_raw_extargs ext arguments - * @ingroup tcp_raw - * Additional data storage per tcp pcb\n - * @see @ref tcp_raw - * - * When LWIP_TCP_PCB_NUM_EXT_ARGS is > 0, every tcp pcb (including listen pcb) - * includes a number of additional argument entries in an array. - * - * To support memory management, in addition to a 'void *', callbacks can be - * provided to manage transition from listening pcbs to connections and to - * deallocate memory when a pcb is deallocated (see struct @ref tcp_ext_arg_callbacks). - * - * After allocating this index, use @ref tcp_ext_arg_set and @ref tcp_ext_arg_get - * to store and load arguments from this index for a given pcb. - */ - -static u8_t tcp_ext_arg_id; - -/** - * @ingroup tcp_raw_extargs - * Allocate an index to store data in ext_args member of struct tcp_pcb. - * Returned value is an index in mentioned array. - * The index is *global* over all pcbs! - * - * When @ref LWIP_TCP_PCB_NUM_EXT_ARGS is > 0, every tcp pcb (including listen pcb) - * includes a number of additional argument entries in an array. - * - * To support memory management, in addition to a 'void *', callbacks can be - * provided to manage transition from listening pcbs to connections and to - * deallocate memory when a pcb is deallocated (see struct @ref tcp_ext_arg_callbacks). - * - * After allocating this index, use @ref tcp_ext_arg_set and @ref tcp_ext_arg_get - * to store and load arguments from this index for a given pcb. - * - * @return a unique index into struct tcp_pcb.ext_args - */ -u8_t -tcp_ext_arg_alloc_id(void) -{ - u8_t result = tcp_ext_arg_id; - tcp_ext_arg_id++; - - LWIP_ASSERT_CORE_LOCKED(); - -#if LWIP_TCP_PCB_NUM_EXT_ARGS >= 255 -#error LWIP_TCP_PCB_NUM_EXT_ARGS -#endif - LWIP_ASSERT("Increase LWIP_TCP_PCB_NUM_EXT_ARGS in lwipopts.h", result < LWIP_TCP_PCB_NUM_EXT_ARGS); - return result; -} - -/** - * @ingroup tcp_raw_extargs - * Set callbacks for a given index of ext_args on the specified pcb. - * - * @param pcb tcp_pcb for which to set the callback - * @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id) - * @param callbacks callback table (const since it is referenced, not copied!) - */ -void -tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, uint8_t id, const struct tcp_ext_arg_callbacks * const callbacks) -{ - LWIP_ASSERT("pcb != NULL", pcb != NULL); - LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS); - LWIP_ASSERT("callbacks != NULL", callbacks != NULL); - - LWIP_ASSERT_CORE_LOCKED(); - - pcb->ext_args[id].callbacks = callbacks; -} - -/** - * @ingroup tcp_raw_extargs - * Set data for a given index of ext_args on the specified pcb. - * - * @param pcb tcp_pcb for which to set the data - * @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id) - * @param arg data pointer to set - */ -void tcp_ext_arg_set(struct tcp_pcb *pcb, uint8_t id, void *arg) -{ - LWIP_ASSERT("pcb != NULL", pcb != NULL); - LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS); - - LWIP_ASSERT_CORE_LOCKED(); - - pcb->ext_args[id].data = arg; -} - -/** - * @ingroup tcp_raw_extargs - * Set data for a given index of ext_args on the specified pcb. - * - * @param pcb tcp_pcb for which to set the data - * @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id) - * @return data pointer at the given index - */ -void *tcp_ext_arg_get(const struct tcp_pcb *pcb, uint8_t id) -{ - LWIP_ASSERT("pcb != NULL", pcb != NULL); - LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS); - - LWIP_ASSERT_CORE_LOCKED(); - - return pcb->ext_args[id].data; -} - -/** This function calls the "destroy" callback for all ext_args once a pcb is - * freed. - */ -static void -tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args) -{ - int i; - LWIP_ASSERT("ext_args != NULL", ext_args != NULL); - - for (i = 0; i < LWIP_TCP_PCB_NUM_EXT_ARGS; i++) { - if (ext_args[i].callbacks != NULL) { - if (ext_args[i].callbacks->destroy != NULL) { - ext_args[i].callbacks->destroy((u8_t)i, ext_args[i].data); - } - } - } -} - -/** This function calls the "passive_open" callback for all ext_args if a connection - * is in the process of being accepted. This is called just after the SYN is - * received and before a SYN/ACK is sent, to allow to modify the very first - * segment sent even on passive open. Naturally, the "accepted" callback of the - * pcb has not been called yet! - */ -err_t -tcp_ext_arg_invoke_callbacks_passive_open(struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb) -{ - int i; - LWIP_ASSERT("lpcb != NULL", lpcb != NULL); - LWIP_ASSERT("cpcb != NULL", cpcb != NULL); - - for (i = 0; i < LWIP_TCP_PCB_NUM_EXT_ARGS; i++) { - if (lpcb->ext_args[i].callbacks != NULL) { - if (lpcb->ext_args[i].callbacks->passive_open != NULL) { - err_t err = lpcb->ext_args[i].callbacks->passive_open((u8_t)i, lpcb, cpcb); - if (err != ERR_OK) { - return err; - } - } - } - } - return ERR_OK; -} -#endif /* LWIP_TCP_PCB_NUM_EXT_ARGS */ - -#endif /* LWIP_TCP */ diff --git a/core/c/core/tcp_in.c b/core/c/core/tcp_in.c deleted file mode 100755 index 720bdb6..0000000 --- a/core/c/core/tcp_in.c +++ /dev/null @@ -1,2194 +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/priv/tcp_priv.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/ip6.h" -#include "lwip/ip6_addr.h" -#if LWIP_ND6_TCP_REACHABILITY_HINTS -#include "lwip/nd6.h" -#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ - -#include - -#ifdef LWIP_HOOK_FILENAME -#include LWIP_HOOK_FILENAME -#endif - -/** Initial CWND calculation as defined RFC 2581 */ -#define LWIP_TCP_CALC_INITIAL_CWND(mss) ((tcpwnd_size_t)LWIP_MIN((4U * (mss)), LWIP_MAX((2U * (mss)), 4380U))) - -/* 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; -static struct tcp_hdr *tcphdr; -static u16_t tcphdr_optlen; -static u16_t tcphdr_opt1len; -static u8_t *tcphdr_opt2; -static u16_t tcp_optidx; -static u32_t seqno, ackno; -static tcpwnd_size_t recv_acked; -static u16_t tcplen; -static u8_t flags; - -static u8_t recv_flags; -static struct pbuf *recv_data; - -struct tcp_pcb *tcp_input_pcb; - -/* Forward declarations. */ -static err_t tcp_process(struct tcp_pcb *pcb); -static void tcp_receive(struct tcp_pcb *pcb); -static void tcp_parseopt(struct tcp_pcb *pcb); - -static void tcp_listen_input(struct tcp_pcb_listen *pcb); -static void tcp_timewait_input(struct tcp_pcb *pcb); - -static int tcp_input_delayed_close(struct tcp_pcb *pcb); - -#if LWIP_TCP_SACK_OUT -static void tcp_add_sack(struct tcp_pcb *pcb, u32_t left, u32_t right); -static void tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq); -#if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) -static void tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq); -#endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ -#endif /* LWIP_TCP_SACK_OUT */ - -/** - * 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 TCP header) - * @param inp network interface on which this segment was received - */ -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_bytes; - err_t err; - - LWIP_UNUSED_ARG(inp); - LWIP_ASSERT_CORE_LOCKED(); - LWIP_ASSERT("tcp_input: invalid pbuf", p != NULL); - - PERF_START; - - TCP_STATS_INC(tcp.recv); - MIB2_STATS_INC(mib2.tcpinsegs); - - tcphdr = (struct tcp_hdr *)p->payload; - -#if TCP_INPUT_DEBUG - tcp_debug_print(tcphdr); -#endif - - /* Check that TCP header fits in payload */ - if (p->len < TCP_HLEN) { - /* 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); - goto dropped; - } - - /* Don't even process incoming broadcasts/multicasts. */ - if (ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()) || - ip_addr_ismulticast(ip_current_dest_addr())) { - TCP_STATS_INC(tcp.proterr); - goto dropped; - } - -#if CHECKSUM_CHECK_TCP - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_TCP) { - /* Verify TCP checksum. */ - u16_t chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - ip_current_src_addr(), ip_current_dest_addr()); - if (chksum != 0) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", - chksum)); - tcp_debug_print(tcphdr); - TCP_STATS_INC(tcp.chkerr); - goto dropped; - } - } -#endif /* CHECKSUM_CHECK_TCP */ - - /* sanity-check header length */ - hdrlen_bytes = TCPH_HDRLEN_BYTES(tcphdr); - if ((hdrlen_bytes < TCP_HLEN) || (hdrlen_bytes > p->tot_len)) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: invalid header length (%"U16_F")\n", (u16_t)hdrlen_bytes)); - TCP_STATS_INC(tcp.lenerr); - goto dropped; - } - - /* Move the payload pointer in the pbuf so that it points to the - TCP data instead of the TCP header. */ - tcphdr_optlen = (u16_t)(hdrlen_bytes - TCP_HLEN); - tcphdr_opt2 = NULL; - if (p->len >= hdrlen_bytes) { - /* all options are in the first pbuf */ - tcphdr_opt1len = tcphdr_optlen; - pbuf_remove_header(p, hdrlen_bytes); /* cannot fail */ - } else { - u16_t opt2len; - /* TCP header fits into first pbuf, options don't - data is in the next pbuf */ - /* there must be a next pbuf, due to hdrlen_bytes sanity check above */ - LWIP_ASSERT("p->next != NULL", p->next != NULL); - - /* advance over the TCP header (cannot fail) */ - pbuf_remove_header(p, TCP_HLEN); - - /* determine how long the first and second parts of the options are */ - tcphdr_opt1len = p->len; - opt2len = (u16_t)(tcphdr_optlen - tcphdr_opt1len); - - /* options continue in the next pbuf: set p to zero length and hide the - options in the next pbuf (adjusting p->tot_len) */ - pbuf_remove_header(p, tcphdr_opt1len); - - /* check that the options fit in the second pbuf */ - if (opt2len > p->next->len) { - /* drop short packets */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: options overflow second pbuf (%"U16_F" bytes)\n", p->next->len)); - TCP_STATS_INC(tcp.lenerr); - goto dropped; - } - - /* remember the pointer to the second part of the options */ - tcphdr_opt2 = (u8_t *)p->next->payload; - - /* advance p->next to point after the options, and manually - adjust p->tot_len to keep it consistent with the changed p->next */ - pbuf_remove_header(p->next, opt2len); - p->tot_len = (u16_t)(p->tot_len - opt2len); - - LWIP_ASSERT("p->len == 0", p->len == 0); - LWIP_ASSERT("p->tot_len == p->next->tot_len", p->tot_len == p->next->tot_len); - } - - /* Convert fields in TCP header to host byte order. */ - tcphdr->src = lwip_ntohs(tcphdr->src); - tcphdr->dest = lwip_ntohs(tcphdr->dest); - seqno = tcphdr->seqno = lwip_ntohl(tcphdr->seqno); - ackno = tcphdr->ackno = lwip_ntohl(tcphdr->ackno); - tcphdr->wnd = lwip_ntohs(tcphdr->wnd); - - flags = TCPH_FLAGS(tcphdr); - tcplen = p->tot_len; - if (flags & (TCP_FIN | TCP_SYN)) { - tcplen++; - if (tcplen < p->tot_len) { - /* u16_t overflow, cannot handle this */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: length u16_t overflow, cannot handle this\n")); - TCP_STATS_INC(tcp.lenerr); - goto dropped; - } - } - - /* 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); - - /* check if PCB is bound to specific netif */ - if ((pcb->netif_idx != NETIF_NO_INDEX) && - (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { - prev = pcb; - continue; - } - - if (pcb->remote_port == tcphdr->src && - pcb->local_port == tcphdr->dest && - ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && - ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { - /* 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; - } else { - TCP_STATS_INC(tcp.cachehit); - } - LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); - break; - } - 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) { - LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); - - /* check if PCB is bound to specific netif */ - if ((pcb->netif_idx != NETIF_NO_INDEX) && - (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { - continue; - } - - if (pcb->remote_port == tcphdr->src && - pcb->local_port == tcphdr->dest && - ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && - ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { - /* 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")); -#ifdef LWIP_HOOK_TCP_INPACKET_PCB - if (LWIP_HOOK_TCP_INPACKET_PCB(pcb, tcphdr, tcphdr_optlen, tcphdr_opt1len, - tcphdr_opt2, p) == ERR_OK) -#endif - { - tcp_timewait_input(pcb); - } - 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) { -#if TUN2SOCKS - // go-tun2socks logic - // use the first one, and it should be set to the loopif - break; -#endif /* TUN2SOCKS */ - - /* check if PCB is bound to specific netif */ - if ((lpcb->netif_idx != NETIF_NO_INDEX) && - (lpcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { - prev = (struct tcp_pcb *)lpcb; - continue; - } - - if (lpcb->local_port == tcphdr->dest) { - if (IP_IS_ANY_TYPE_VAL(lpcb->local_ip)) { - /* found an ANY TYPE (IPv4/IPv6) match */ -#if SO_REUSE - lpcb_any = lpcb; - lpcb_prev = prev; -#else /* SO_REUSE */ - break; -#endif /* SO_REUSE */ - } else if (IP_ADDR_PCB_VERSION_MATCH_EXACT(lpcb, ip_current_dest_addr())) { - if (ip_addr_cmp(&lpcb->local_ip, ip_current_dest_addr())) { - /* found an exact match */ - break; - } else if (ip_addr_isany(&lpcb->local_ip)) { - /* found an ANY-match */ -#if SO_REUSE - lpcb_any = lpcb; - lpcb_prev = prev; -#else /* SO_REUSE */ - 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; - } else { - TCP_STATS_INC(tcp.cachehit); - } - - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); -#ifdef LWIP_HOOK_TCP_INPACKET_PCB - if (LWIP_HOOK_TCP_INPACKET_PCB((struct tcp_pcb *)lpcb, tcphdr, tcphdr_optlen, - tcphdr_opt1len, tcphdr_opt2, p) == ERR_OK) -#endif - { - tcp_listen_input(lpcb); - } - 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 */ - - -#ifdef LWIP_HOOK_TCP_INPACKET_PCB - if ((pcb != NULL) && LWIP_HOOK_TCP_INPACKET_PCB(pcb, tcphdr, tcphdr_optlen, - tcphdr_opt1len, tcphdr_opt2, p) != ERR_OK) { - pbuf_free(p); - return; - } -#endif - if (pcb != NULL) { - /* The incoming segment belongs to a connection. */ -#if TCP_INPUT_DEBUG - tcp_debug_print_state(pcb->state); -#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; - recv_acked = 0; - - if (flags & TCP_PSH) { - p->flags |= PBUF_FLAG_PUSH; - } - - /* If there is data which was previously "refused" by upper layer */ - if (pcb->refused_data != NULL) { - if ((tcp_process_refused_data(pcb) == ERR_ABRT) || - ((pcb->refused_data != NULL) && (tcplen > 0))) { - /* pcb has been aborted or refused data is still refused and the new - segment contains data */ - if (pcb->rcv_ann_wnd == 0) { - /* this is a zero-window probe, we respond to it with current RCV.NXT - and drop the data segment */ - tcp_send_empty_ack(pcb); - } - TCP_STATS_INC(tcp.drop); - MIB2_STATS_INC(mib2.tcpinerrs); - goto aborted; - } - } - 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->state, pcb->errf, pcb->callback_arg, ERR_RST); - tcp_pcb_remove(&tcp_active_pcbs, pcb); - tcp_free(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 (recv_acked > 0) { - u16_t acked16; -#if LWIP_WND_SCALE - /* recv_acked is u32_t but the sent callback only takes a u16_t, - so we might have to call it multiple times. */ - u32_t acked = recv_acked; - while (acked > 0) { - acked16 = (u16_t)LWIP_MIN(acked, 0xffffu); - acked -= acked16; -#else - { - acked16 = recv_acked; -#endif - TCP_EVENT_SENT(pcb, (u16_t)acked16, err); - if (err == ERR_ABRT) { - goto aborted; - } - } - recv_acked = 0; - } - if (tcp_input_delayed_close(pcb)) { - goto aborted; - } -#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE - while (recv_data != NULL) { - struct pbuf *rest = NULL; - pbuf_split_64k(recv_data, &rest); -#else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - if (recv_data != NULL) { -#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - - 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); -#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE - if (rest != NULL) { - pbuf_free(rest); - } -#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - tcp_abort(pcb); - goto aborted; - } - - /* Notify application that data has been received. */ - TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); - if (err == ERR_ABRT) { -#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE - if (rest != NULL) { - pbuf_free(rest); - } -#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - goto aborted; - } - - /* If the upper layer can't receive this data, store it */ - if (err != ERR_OK) { -#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE - if (rest != NULL) { - pbuf_cat(recv_data, rest); - } -#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - pcb->refused_data = recv_data; - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); -#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE - break; - } else { - /* Upper layer received the data, go on with the rest if > 64K */ - recv_data = rest; -#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - } - } - - /* If a FIN segment was received, we call the callback - function with a NULL buffer to indicate EOF. */ - if (recv_flags & TF_GOT_FIN) { - if (pcb->refused_data != NULL) { - /* Delay this if we have refused data. */ - pcb->refused_data->flags |= PBUF_FLAG_TCP_FIN; - } else { - /* correct rcv_wnd as the application won't call tcp_recved() - for the FIN's seqno */ - if (pcb->rcv_wnd != TCP_WND_MAX(pcb)) { - pcb->rcv_wnd++; - } - TCP_EVENT_CLOSED(pcb, err); - if (err == ERR_ABRT) { - goto aborted; - } - } - } - - tcp_input_pcb = NULL; - if (tcp_input_delayed_close(pcb)) { - goto aborted; - } - /* 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); - inseg.p = NULL; - } - } 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_rst(NULL, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } - pbuf_free(p); - } - - LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); - PERF_STOP("tcp_input"); - return; -dropped: - TCP_STATS_INC(tcp.drop); - MIB2_STATS_INC(mib2.tcpinerrs); - pbuf_free(p); -} - -/** Called from tcp_input to check for TF_CLOSED flag. This results in closing - * and deallocating a pcb at the correct place to ensure noone references it - * any more. - * @returns 1 if the pcb has been closed and deallocated, 0 otherwise - */ -static int -tcp_input_delayed_close(struct tcp_pcb *pcb) -{ - LWIP_ASSERT("tcp_input_delayed_close: invalid pcb", pcb != NULL); - - 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->state, pcb->errf, pcb->callback_arg, ERR_CLSD); - } - tcp_pcb_remove(&tcp_active_pcbs, pcb); - tcp_free(pcb); - return 1; - } - return 0; -} - -/** - * 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 - * - * @note the segment which arrived is saved in global variables, therefore only the pcb - * involved is passed as a parameter to this function - */ -static void -tcp_listen_input(struct tcp_pcb_listen *pcb) -{ - struct tcp_pcb *npcb; - u32_t iss; - err_t rc; - - if (flags & TCP_RST) { - /* An incoming RST should be ignored. Return. */ - return; - } - - LWIP_ASSERT("tcp_listen_input: invalid pcb", pcb != NULL); - - /* 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((const struct tcp_pcb *)pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } else if (flags & TCP_SYN) { - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); -#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; - } -#endif /* TCP_LISTEN_BACKLOG */ - 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) { - err_t err; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); - TCP_STATS_INC(tcp.memerr); - TCP_EVENT_ACCEPT(pcb, NULL, pcb->callback_arg, ERR_MEM, err); - LWIP_UNUSED_ARG(err); /* err not useful here */ - return; - } -#if TCP_LISTEN_BACKLOG - pcb->accepts_pending++; - tcp_set_flags(npcb, TF_BACKLOGPEND); -#endif /* TCP_LISTEN_BACKLOG */ - /* Set up the new PCB. */ - ip_addr_copy(npcb->local_ip, *ip_current_dest_addr()); - ip_addr_copy(npcb->remote_ip, *ip_current_src_addr()); - npcb->local_port = pcb->local_port; - -#if TUN2SOCKS - // go-tun2socks logic - // Always reset local port to the dest of the connection, because we are - // accepting all incomming connections, regardless of there destination addresses, - // as such, npcb is acting as the server socket that communicates with the - // client socket. - npcb->local_port = tcphdr->dest; -#endif /* TUN2SOCKS */ - - npcb->remote_port = tcphdr->src; - npcb->state = SYN_RCVD; - npcb->rcv_nxt = seqno + 1; - npcb->rcv_ann_right_edge = npcb->rcv_nxt; - iss = tcp_next_iss(npcb); - npcb->snd_wl2 = iss; - npcb->snd_nxt = iss; - npcb->lastack = iss; - npcb->snd_lbb = iss; - npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ - npcb->callback_arg = pcb->callback_arg; -#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG - npcb->listener = pcb; -#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ - /* inherit socket options */ - npcb->so_options = pcb->so_options & SOF_INHERITED; - npcb->netif_idx = pcb->netif_idx; - /* Register the new PCB so that we can begin receiving segments - for it. */ - TCP_REG_ACTIVE(npcb); - - /* Parse any options in the SYN. */ - tcp_parseopt(npcb); - npcb->snd_wnd = tcphdr->wnd; - npcb->snd_wnd_max = npcb->snd_wnd; - -#if TCP_CALCULATE_EFF_SEND_MSS - npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip); -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - - MIB2_STATS_INC(mib2.tcppassiveopens); - -#if LWIP_TCP_PCB_NUM_EXT_ARGS - if (tcp_ext_arg_invoke_callbacks_passive_open(pcb, npcb) != ERR_OK) { - tcp_abandon(npcb, 0); - return; - } -#endif - - /* 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; - } - tcp_output(npcb); - } - return; -} - -/** - * 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 - */ -static void -tcp_timewait_input(struct tcp_pcb *pcb) -{ - /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */ - /* RFC 793 3.9 Event Processing - Segment Arrives: - * - first check sequence number - we skip that one in TIME_WAIT (always - * acceptable since we only send ACKs) - * - second check the RST bit (... return) */ - if (flags & TCP_RST) { - return; - } - - LWIP_ASSERT("tcp_timewait_input: invalid pcb", pcb != NULL); - - /* - fourth, check the SYN bit, */ - if (flags & TCP_SYN) { - /* If an incoming segment is not acceptable, an acknowledgment - should be sent in reply */ - if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd)) { - /* If the SYN is in the window it is an error, send a reset */ - tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - return; - } - } else if (flags & TCP_FIN) { - /* - eighth, check the FIN bit: Remain in the TIME-WAIT state. - Restart the 2 MSL time-wait timeout.*/ - pcb->tmr = tcp_ticks; - } - - if ((tcplen > 0)) { - /* Acknowledge data, FIN or out-of-window SYN */ - tcp_ack_now(pcb); - tcp_output(pcb); - } - return; -} - -/** - * 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; - - LWIP_ASSERT("tcp_process: invalid pcb", pcb != NULL); - - /* Process incoming RST segments. */ - if (flags & TCP_RST) { - /* First, determine if the reset is acceptable. */ - if (pcb->state == SYN_SENT) { - /* "In the SYN-SENT state (a RST received in response to an initial SYN), - the RST is acceptable if the ACK field acknowledges the SYN." */ - if (ackno == pcb->snd_nxt) { - acceptable = 1; - } - } else { - /* "In all states except SYN-SENT, all reset (RST) segments are validated - by checking their SEQ-fields." */ - if (seqno == pcb->rcv_nxt) { - acceptable = 1; - } else if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, - pcb->rcv_nxt + pcb->rcv_wnd)) { - /* If the sequence number is inside the window, we send a challenge ACK - and wait for a re-send with matching sequence number. - This follows RFC 5961 section 3.2 and addresses CVE-2004-0230 - (RST spoofing attack), which is present in RFC 793 RST handling. */ - tcp_ack_now(pcb); - } - } - - 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; - tcp_clear_flags(pcb, 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; - pcb->persist_probe = 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, lwip_ntohl(pcb->unacked->tcphdr->seqno))); - /* received SYN ACK with expected sequence number? */ - if ((flags & TCP_ACK) && (flags & TCP_SYN) - && (ackno == pcb->lastack + 1)) { - pcb->rcv_nxt = seqno + 1; - pcb->rcv_ann_right_edge = pcb->rcv_nxt; - pcb->lastack = ackno; - pcb->snd_wnd = tcphdr->wnd; - pcb->snd_wnd_max = pcb->snd_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->local_ip, &pcb->remote_ip); -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - - pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SENT): cwnd %"TCPWNDSIZE_F - " ssthresh %"TCPWNDSIZE_F"\n", - pcb->cwnd, pcb->ssthresh)); - LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0)); - --pcb->snd_queuelen; - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"TCPWNDSIZE_F"\n", (tcpwnd_size_t)pcb->snd_queuelen)); - rseg = pcb->unacked; - if (rseg == NULL) { - /* might happen if tcp_output fails in tcp_rexmit_rto() - in which case the segment is on the unsent list */ - rseg = pcb->unsent; - LWIP_ASSERT("no segment to free", rseg != NULL); - pcb->unsent = rseg->next; - } else { - pcb->unacked = rseg->next; - } - tcp_seg_free(rseg); - - /* 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; - } - - /* Call the user specified function to call when successfully - * 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(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - /* Resend SYN immediately (don't wait for rto timeout) to establish - connection faster, but do not send more SYNs than we otherwise would - have, or we might get caught in a loop on loopback interfaces. */ - if (pcb->nrtx < TCP_SYNMAXRTX) { - pcb->rtime = 0; - tcp_rexmit_rto(pcb); - } - } - break; - case SYN_RCVD: - if (flags & TCP_ACK) { - /* expected ACK number? */ - if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) { - 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 || TCP_LISTEN_BACKLOG - if (pcb->listener == NULL) { - /* listen pcb might be closed by now */ - err = ERR_VAL; - } else -#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ - { -#if LWIP_CALLBACK_API - LWIP_ASSERT("pcb->listener->accept != NULL", pcb->listener->accept != NULL); -#endif - tcp_backlog_accepted(pcb); - /* Call the accept function. */ - TCP_EVENT_ACCEPT(pcb->listener, pcb, pcb->callback_arg, 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; - } - /* 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 (recv_acked != 0) { - recv_acked--; - } - - pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SYN_RCVD): cwnd %"TCPWNDSIZE_F - " ssthresh %"TCPWNDSIZE_F"\n", - pcb->cwnd, pcb->ssthresh)); - - if (recv_flags & TF_GOT_FIN) { - tcp_ack_now(pcb); - pcb->state = CLOSE_WAIT; - } - } else { - /* incorrect ACK number, send RST */ - tcp_rst(pcb, 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) && - pcb->unsent == NULL) { - 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_ACTIVE(pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); - } else { - tcp_ack_now(pcb); - pcb->state = CLOSING; - } - } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) && - pcb->unsent == NULL) { - 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_ACTIVE(pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); - } - break; - case CLOSING: - tcp_receive(pcb); - if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) { - 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_ACTIVE(pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); - } - break; - case LAST_ACK: - tcp_receive(pcb); - if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) { - 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 -tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) -{ - struct tcp_seg *old_seg; - - LWIP_ASSERT("tcp_oos_insert_segment: invalid cseg", cseg != NULL); - - 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 */ - -/** Remove segments from a list if the incoming ACK acknowledges them */ -static struct tcp_seg * -tcp_free_acked_segments(struct tcp_pcb *pcb, struct tcp_seg *seg_list, const char *dbg_list_name, - struct tcp_seg *dbg_other_seg_list) -{ - struct tcp_seg *next; - u16_t clen; - - LWIP_UNUSED_ARG(dbg_list_name); - LWIP_UNUSED_ARG(dbg_other_seg_list); - - while (seg_list != NULL && - TCP_SEQ_LEQ(lwip_ntohl(seg_list->tcphdr->seqno) + - TCP_TCPLEN(seg_list), ackno)) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->%s\n", - lwip_ntohl(seg_list->tcphdr->seqno), - lwip_ntohl(seg_list->tcphdr->seqno) + TCP_TCPLEN(seg_list), - dbg_list_name)); - - next = seg_list; - seg_list = seg_list->next; - - clen = pbuf_clen(next->p); - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ", - (tcpwnd_size_t)pcb->snd_queuelen)); - LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= clen)); - - pcb->snd_queuelen = (u16_t)(pcb->snd_queuelen - clen); - recv_acked = (tcpwnd_size_t)(recv_acked + next->len); - tcp_seg_free(next); - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing %s)\n", - (tcpwnd_size_t)pcb->snd_queuelen, - dbg_list_name)); - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_receive: valid queue length", - seg_list != NULL || dbg_other_seg_list != NULL); - } - } - return seg_list; -} - -/** - * 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, it 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 - * 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) -{ - s16_t m; - u32_t right_wnd_edge; - int found_dupack = 0; - - LWIP_ASSERT("tcp_receive: invalid pcb", pcb != NULL); - LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); - - if (flags & TCP_ACK) { - right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; - - /* Update window. */ - if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || - (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || - (pcb->snd_wl2 == ackno && (u32_t)SND_WND_SCALE(pcb, tcphdr->wnd) > pcb->snd_wnd)) { - pcb->snd_wnd = SND_WND_SCALE(pcb, tcphdr->wnd); - /* keep track of the biggest window announced by the remote host to calculate - the maximum segment size */ - if (pcb->snd_wnd_max < pcb->snd_wnd) { - pcb->snd_wnd_max = pcb->snd_wnd; - } - pcb->snd_wl1 = seqno; - pcb->snd_wl2 = ackno; - LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"TCPWNDSIZE_F"\n", pcb->snd_wnd)); -#if TCP_WND_DEBUG - } else { - if (pcb->snd_wnd != (tcpwnd_size_t)SND_WND_SCALE(pcb, 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) - * - * 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)) { - /* 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 ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) { - ++pcb->dupacks; - } - if (pcb->dupacks > 3) { - /* Inflate the congestion window */ - TCP_WND_INC(pcb->cwnd, pcb->mss); - } - if (pcb->dupacks >= 3) { - /* Do fast retransmit (checked via TF_INFR, not via dupacks count) */ - 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)) { - /* We come here when the ACK acknowledges new data. */ - tcpwnd_size_t acked; - - /* Reset the "IN Fast Retransmit" flag, since we are no longer - in fast retransmit. Also reset the congestion window to the - slow start threshold. */ - if (pcb->flags & TF_INFR) { - tcp_clear_flags(pcb, TF_INFR); - pcb->cwnd = pcb->ssthresh; - pcb->bytes_acked = 0; - } - - /* Reset the number of retransmissions. */ - pcb->nrtx = 0; - - /* Reset the retransmission time-out. */ - pcb->rto = (s16_t)((pcb->sa >> 3) + pcb->sv); - - /* Record how much data this ACK acks */ - acked = (tcpwnd_size_t)(ackno - pcb->lastack); - - /* 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) { - tcpwnd_size_t increase; - /* limit to 1 SMSS segment during period following RTO */ - u8_t num_seg = (pcb->flags & TF_RTO) ? 1 : 2; - /* RFC 3465, section 2.2 Slow Start */ - increase = LWIP_MIN(acked, (tcpwnd_size_t)(num_seg * pcb->mss)); - TCP_WND_INC(pcb->cwnd, increase); - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd)); - } else { - /* RFC 3465, section 2.1 Congestion Avoidance */ - TCP_WND_INC(pcb->bytes_acked, acked); - if (pcb->bytes_acked >= pcb->cwnd) { - pcb->bytes_acked = (tcpwnd_size_t)(pcb->bytes_acked - pcb->cwnd); - TCP_WND_INC(pcb->cwnd, pcb->mss); - } - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"TCPWNDSIZE_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 ? - lwip_ntohl(pcb->unacked->tcphdr->seqno) : 0, - pcb->unacked != NULL ? - lwip_ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked) : 0)); - - /* Remove segment from the unacknowledged list if the incoming - ACK acknowledges them. */ - pcb->unacked = tcp_free_acked_segments(pcb, pcb->unacked, "unacked", pcb->unsent); - /* 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. */ - pcb->unsent = tcp_free_acked_segments(pcb, pcb->unsent, "unsent", pcb->unacked); - - /* 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; - -#if TCP_OVERSIZE - if (pcb->unsent == NULL) { - pcb->unsent_oversize = 0; - } -#endif /* TCP_OVERSIZE */ - -#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS - if (ip_current_is_v6()) { - /* Inform neighbor reachability of forward progress. */ - nd6_reachability_hint(ip6_current_src_addr()); - } -#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ - - pcb->snd_buf = (tcpwnd_size_t)(pcb->snd_buf + recv_acked); - /* check if this ACK ends our retransmission of in-flight data */ - if (pcb->flags & TF_RTO) { - /* RTO is done if - 1) both queues are empty or - 2) unacked is empty and unsent head contains data not part of RTO or - 3) unacked head contains data not part of RTO */ - if (pcb->unacked == NULL) { - if ((pcb->unsent == NULL) || - (TCP_SEQ_LEQ(pcb->rto_end, lwip_ntohl(pcb->unsent->tcphdr->seqno)))) { - tcp_clear_flags(pcb, TF_RTO); - } - } else if (TCP_SEQ_LEQ(pcb->rto_end, lwip_ntohl(pcb->unacked->tcphdr->seqno))) { - tcp_clear_flags(pcb, TF_RTO); - } - } - /* End of ACK for new data processing. */ - } else { - /* Out of sequence ACK, didn't really ack anything */ - tcp_send_empty_ack(pcb); - } - - 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)) { - /* 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); - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", - m, (u16_t)(m * TCP_SLOW_INTERVAL))); - - /* This is taken directly from VJs original code in his paper */ - m = (s16_t)(m - (pcb->sa >> 3)); - pcb->sa = (s16_t)(pcb->sa + m); - if (m < 0) { - m = (s16_t) - m; - } - m = (s16_t)(m - (pcb->sv >> 2)); - pcb->sv = (s16_t)(pcb->sv + m); - pcb->rto = (s16_t)((pcb->sa >> 3) + pcb->sv); - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", - pcb->rto, (u16_t)(pcb->rto * TCP_SLOW_INTERVAL))); - - pcb->rttest = 0; - } - } - - /* If the incoming segment contains data, we must process it - further unless the pcb already received a FIN. - (RFC 793, chapter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, CLOSING, - LAST-ACK and TIME-WAIT: "Ignore the segment text.") */ - if ((tcplen > 0) && (pcb->state < CLOSE_WAIT)) { - /* 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)) { - /* 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.*/ - - struct pbuf *p = inseg.p; - u32_t off32 = pcb->rcv_nxt - seqno; - u16_t new_tot_len, off; - LWIP_ASSERT("inseg.p != NULL", inseg.p); - LWIP_ASSERT("insane offset!", (off32 < 0xffff)); - off = (u16_t)off32; - LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); - inseg.len -= off; - new_tot_len = (u16_t)(inseg.p->tot_len - off); - while (p->len < off) { - off -= p->len; - /* all pbufs up to and including this one have len==0, so tot_len is equal */ - p->tot_len = new_tot_len; - p->len = 0; - p = p->next; - } - /* cannot fail... */ - pbuf_remove_header(p, off); - inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; - } else { - if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)) { - /* the whole segment is < rcv_nxt */ - /* must be a duplicate of a packet that has already been correctly handled */ - - 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)) { - 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) & ~(unsigned int)TCP_FIN); - } - /* Adjust length of segment to fit in the window. */ - TCPWND_CHECK16(pcb->rcv_wnd); - inseg.len = (u16_t)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 { - struct tcp_seg *next = pcb->ooseq; - /* Remove all segments on ooseq that are covered by inseg already. - * FIN is copied from ooseq to inseg if present. */ - while (next && - TCP_SEQ_GEQ(seqno + tcplen, - next->tcphdr->seqno + next->len)) { - struct tcp_seg *tmp; - /* inseg cannot have FIN here (already processed above) */ - if ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0 && - (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { - TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); - tcplen = TCP_TCPLEN(&inseg); - } - tmp = next; - next = next->next; - tcp_seg_free(tmp); - } - /* 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) { - - struct tcp_seg *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. */ - /* With window scaling, this can overflow recv_data->tot_len, but - that's not a problem since we explicitly fix that before passing - recv_data 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); - } -#if LWIP_TCP_SACK_OUT - if (pcb->flags & TF_SACK) { - if (pcb->ooseq != NULL) { - /* Some segments may have been removed from ooseq, let's remove all SACKs that - describe anything before the new beginning of that list. */ - tcp_remove_sacks_lt(pcb, pcb->ooseq->tcphdr->seqno); - } else if (LWIP_TCP_SACK_VALID(pcb, 0)) { - /* ooseq has been cleared. Nothing to SACK */ - memset(pcb->rcv_sacks, 0, sizeof(pcb->rcv_sacks)); - } - } -#endif /* LWIP_TCP_SACK_OUT */ -#endif /* TCP_QUEUE_OOSEQ */ - - - /* Acknowledge the segment(s). */ - tcp_ack(pcb); - -#if LWIP_TCP_SACK_OUT - if (LWIP_TCP_SACK_VALID(pcb, 0)) { - /* Normally the ACK for the data received could be piggy-backed on a data packet, - but lwIP currently does not support including SACKs in data packets. So we force - it to respond with an empty ACK packet (only if there is at least one SACK to be sent). - NOTE: tcp_send_empty_ack() on success clears the ACK flags (set by tcp_ack()) */ - tcp_send_empty_ack(pcb); - } -#endif /* LWIP_TCP_SACK_OUT */ - -#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS - if (ip_current_is_v6()) { - /* Inform neighbor reachability of forward progress. */ - nd6_reachability_hint(ip6_current_src_addr()); - } -#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ - - } else { - /* We get here if the incoming segment is out-of-sequence. */ - -#if TCP_QUEUE_OOSEQ - /* We queue the segment on the ->ooseq queue. */ - if (pcb->ooseq == NULL) { - pcb->ooseq = tcp_seg_copy(&inseg); -#if LWIP_TCP_SACK_OUT - if (pcb->flags & TF_SACK) { - /* All the SACKs should be invalid, so we can simply store the most recent one: */ - pcb->rcv_sacks[0].left = seqno; - pcb->rcv_sacks[0].right = seqno + inseg.len; - } -#endif /* LWIP_TCP_SACK_OUT */ - } 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. */ - -#if LWIP_TCP_SACK_OUT - /* This is the left edge of the lowest possible SACK range. - It may start before the newly received segment (possibly adjusted below). */ - u32_t sackbeg = TCP_SEQ_LT(seqno, pcb->ooseq->tcphdr->seqno) ? seqno : pcb->ooseq->tcphdr->seqno; -#endif /* LWIP_TCP_SACK_OUT */ - struct tcp_seg *next, *prev = NULL; - for (next = pcb->ooseq; next != NULL; next = next->next) { - 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. */ - struct tcp_seg *cseg = tcp_seg_copy(&inseg); - if (cseg != NULL) { - if (prev != NULL) { - prev->next = cseg; - } else { - pcb->ooseq = cseg; - } - tcp_oos_insert_segment(cseg, next); - } - break; - } else { - /* Either the lengths 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. */ - struct tcp_seg *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. */ - struct tcp_seg *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 LWIP_TCP_SACK_OUT - /* The new segment goes after the 'next' one. If there is a "hole" in sequence numbers - between 'prev' and the beginning of 'next', we want to move sackbeg. */ - if (prev != NULL && prev->tcphdr->seqno + prev->len != next->tcphdr->seqno) { - sackbeg = next->tcphdr->seqno; - } -#endif /* LWIP_TCP_SACK_OUT */ - - /* We don't use 'prev' below, so let's set it to current 'next'. - This way even if we break the loop below, 'prev' will be pointing - at the segment right in front of the newly added one. */ - prev = next; - - /* 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 (TCP_SEQ_GT((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 = (u16_t)(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; - } - } - } - -#if LWIP_TCP_SACK_OUT - if (pcb->flags & TF_SACK) { - if (prev == NULL) { - /* The new segment is at the beginning. sackbeg should already be set properly. - We need to find the right edge. */ - next = pcb->ooseq; - } else if (prev->next != NULL) { - /* The new segment was added after 'prev'. If there is a "hole" between 'prev' and 'prev->next', - we need to move sackbeg. After that we should find the right edge. */ - next = prev->next; - if (prev->tcphdr->seqno + prev->len != next->tcphdr->seqno) { - sackbeg = next->tcphdr->seqno; - } - } else { - next = NULL; - } - if (next != NULL) { - u32_t sackend = next->tcphdr->seqno; - for ( ; (next != NULL) && (sackend == next->tcphdr->seqno); next = next->next) { - sackend += next->len; - } - tcp_add_sack(pcb, sackbeg, sackend); - } - } -#endif /* LWIP_TCP_SACK_OUT */ - } -#if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) - { - /* Check that the data on ooseq doesn't exceed one of the limits - and throw away everything above that limit. */ -#ifdef TCP_OOSEQ_BYTES_LIMIT - const u32_t ooseq_max_blen = TCP_OOSEQ_BYTES_LIMIT(pcb); - u32_t ooseq_blen = 0; -#endif -#ifdef TCP_OOSEQ_PBUFS_LIMIT - const u16_t ooseq_max_qlen = TCP_OOSEQ_PBUFS_LIMIT(pcb); - u16_t ooseq_qlen = 0; -#endif - struct tcp_seg *next, *prev = NULL; - for (next = pcb->ooseq; next != NULL; prev = next, next = next->next) { - struct pbuf *p = next->p; - int stop_here = 0; -#ifdef TCP_OOSEQ_BYTES_LIMIT - ooseq_blen += p->tot_len; - if (ooseq_blen > ooseq_max_blen) { - stop_here = 1; - } -#endif -#ifdef TCP_OOSEQ_PBUFS_LIMIT - ooseq_qlen += pbuf_clen(p); - if (ooseq_qlen > ooseq_max_qlen) { - stop_here = 1; - } -#endif - if (stop_here) { -#if LWIP_TCP_SACK_OUT - if (pcb->flags & TF_SACK) { - /* Let's remove all SACKs from next's seqno up. */ - tcp_remove_sacks_gt(pcb, next->tcphdr->seqno); - } -#endif /* LWIP_TCP_SACK_OUT */ - /* too much ooseq data, dump this and everything after it */ - tcp_segs_free(next); - if (prev == NULL) { - /* first ooseq segment is too much, dump the whole queue */ - pcb->ooseq = NULL; - } else { - /* just dump 'next' and everything after it */ - prev->next = NULL; - } - break; - } - } - } -#endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ -#endif /* TCP_QUEUE_OOSEQ */ - - /* We send the ACK packet after we've (potentially) dealt with SACKs, - so they can be included in the acknowledgment. */ - tcp_send_empty_ack(pcb); - } - } else { - /* The incoming segment is not within 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_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)) { - tcp_ack_now(pcb); - } - } -} - -static u8_t -tcp_get_next_optbyte(void) -{ - u16_t optidx = tcp_optidx++; - if ((tcphdr_opt2 == NULL) || (optidx < tcphdr_opt1len)) { - u8_t *opts = (u8_t *)tcphdr + TCP_HLEN; - return opts[optidx]; - } else { - u8_t idx = (u8_t)(optidx - tcphdr_opt1len); - return tcphdr_opt2[idx]; - } -} - -/** - * 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) -{ - u8_t data; - u16_t mss; -#if LWIP_TCP_TIMESTAMPS - u32_t tsval; -#endif - - LWIP_ASSERT("tcp_parseopt: invalid pcb", pcb != NULL); - - /* Parse the TCP MSS option, if present. */ - if (tcphdr_optlen != 0) { - for (tcp_optidx = 0; tcp_optidx < tcphdr_optlen; ) { - u8_t opt = tcp_get_next_optbyte(); - switch (opt) { - case LWIP_TCP_OPT_EOL: - /* End of options. */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); - return; - case LWIP_TCP_OPT_NOP: - /* NOP option. */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); - break; - case LWIP_TCP_OPT_MSS: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); - if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_MSS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_MSS) > tcphdr_optlen) { - /* Bad length */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); - return; - } - /* An MSS option with the right option length. */ - mss = (u16_t)(tcp_get_next_optbyte() << 8); - mss |= tcp_get_next_optbyte(); - /* Limit the mss to the configured TCP_MSS and prevent division by zero */ - pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; - break; -#if LWIP_WND_SCALE - case LWIP_TCP_OPT_WS: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: WND_SCALE\n")); - if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_WS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_WS) > tcphdr_optlen) { - /* Bad length */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); - return; - } - /* An WND_SCALE option with the right option length. */ - data = tcp_get_next_optbyte(); - /* If syn was received with wnd scale option, - activate wnd scale opt, but only if this is not a retransmission */ - if ((flags & TCP_SYN) && !(pcb->flags & TF_WND_SCALE)) { - pcb->snd_scale = data; - if (pcb->snd_scale > 14U) { - pcb->snd_scale = 14U; - } - pcb->rcv_scale = TCP_RCV_SCALE; - tcp_set_flags(pcb, TF_WND_SCALE); - /* window scaling is enabled, we can use the full receive window */ - LWIP_ASSERT("window not at default value", pcb->rcv_wnd == TCPWND_MIN16(TCP_WND)); - LWIP_ASSERT("window not at default value", pcb->rcv_ann_wnd == TCPWND_MIN16(TCP_WND)); - pcb->rcv_wnd = pcb->rcv_ann_wnd = TCP_WND; - } - break; -#endif /* LWIP_WND_SCALE */ -#if LWIP_TCP_TIMESTAMPS - case LWIP_TCP_OPT_TS: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); - if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_TS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_TS) > tcphdr_optlen) { - /* Bad length */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); - return; - } - /* TCP timestamp option with valid length */ - tsval = tcp_get_next_optbyte(); - tsval |= (tcp_get_next_optbyte() << 8); - tsval |= (tcp_get_next_optbyte() << 16); - tsval |= (tcp_get_next_optbyte() << 24); - if (flags & TCP_SYN) { - pcb->ts_recent = lwip_ntohl(tsval); - /* Enable sending timestamps in every segment now that we know - the remote host supports it. */ - tcp_set_flags(pcb, TF_TIMESTAMP); - } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno + tcplen)) { - pcb->ts_recent = lwip_ntohl(tsval); - } - /* Advance to next option (6 bytes already read) */ - tcp_optidx += LWIP_TCP_OPT_LEN_TS - 6; - break; -#endif /* LWIP_TCP_TIMESTAMPS */ -#if LWIP_TCP_SACK_OUT - case LWIP_TCP_OPT_SACK_PERM: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: SACK_PERM\n")); - if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_SACK_PERM || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_SACK_PERM) > tcphdr_optlen) { - /* Bad length */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); - return; - } - /* TCP SACK_PERM option with valid length */ - if (flags & TCP_SYN) { - /* We only set it if we receive it in a SYN (or SYN+ACK) packet */ - tcp_set_flags(pcb, TF_SACK); - } - break; -#endif /* LWIP_TCP_SACK_OUT */ - default: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); - data = tcp_get_next_optbyte(); - if (data < 2) { - 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. */ - tcp_optidx += data - 2; - } - } - } -} - -void -tcp_trigger_input_pcb_close(void) -{ - recv_flags |= TF_CLOSED; -} - -#if LWIP_TCP_SACK_OUT -/** - * Called by tcp_receive() to add new SACK entry. - * - * The new SACK entry will be placed at the beginning of rcv_sacks[], as the newest one. - * Existing SACK entries will be "pushed back", to preserve their order. - * This is the behavior described in RFC 2018, section 4. - * - * @param pcb the tcp_pcb for which a segment arrived - * @param left the left side of the SACK (the first sequence number) - * @param right the right side of the SACK (the first sequence number past this SACK) - */ -static void -tcp_add_sack(struct tcp_pcb *pcb, u32_t left, u32_t right) -{ - u8_t i; - u8_t unused_idx; - - if ((pcb->flags & TF_SACK) == 0 || !TCP_SEQ_LT(left, right)) { - return; - } - - /* First, let's remove all SACKs that are no longer needed (because they overlap with the newest one), - while moving all other SACKs forward. - We run this loop for all entries, until we find the first invalid one. - There is no point checking after that. */ - for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { - /* We only want to use SACK at [i] if it doesn't overlap with left:right range. - It does not overlap if its right side is before the newly added SACK, - or if its left side is after the newly added SACK. - NOTE: The equality should not really happen, but it doesn't hurt. */ - if (TCP_SEQ_LEQ(pcb->rcv_sacks[i].right, left) || TCP_SEQ_LEQ(right, pcb->rcv_sacks[i].left)) { - if (unused_idx != i) { - /* We don't need to copy if it's already in the right spot */ - pcb->rcv_sacks[unused_idx] = pcb->rcv_sacks[i]; - } - ++unused_idx; - } - } - - /* Now 'unused_idx' is the index of the first invalid SACK entry, - anywhere between 0 (no valid entries) and LWIP_TCP_MAX_SACK_NUM (all entries are valid). - We want to clear this and all following SACKs. - However, we will be adding another one in the front (and shifting everything else back). - So let's just iterate from the back, and set each entry to the one to the left if it's valid, - or to 0 if it is not. */ - for (i = LWIP_TCP_MAX_SACK_NUM - 1; i > 0; --i) { - /* [i] is the index we are setting, and the value should be at index [i-1], - or 0 if that index is unused (>= unused_idx). */ - if (i - 1 >= unused_idx) { - /* [i-1] is unused. Let's clear [i]. */ - pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; - } else { - pcb->rcv_sacks[i] = pcb->rcv_sacks[i - 1]; - } - } - - /* And now we can store the newest SACK */ - pcb->rcv_sacks[0].left = left; - pcb->rcv_sacks[0].right = right; -} - -/** - * Called to remove a range of SACKs. - * - * SACK entries will be removed or adjusted to not acknowledge any sequence - * numbers that are less than 'seq' passed. It not only invalidates entries, - * but also moves all entries that are still valid to the beginning. - * - * @param pcb the tcp_pcb to modify - * @param seq the lowest sequence number to keep in SACK entries - */ -static void -tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq) -{ - u8_t i; - u8_t unused_idx; - - /* We run this loop for all entries, until we find the first invalid one. - There is no point checking after that. */ - for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { - /* We only want to use SACK at index [i] if its right side is > 'seq'. */ - if (TCP_SEQ_GT(pcb->rcv_sacks[i].right, seq)) { - if (unused_idx != i) { - /* We only copy it if it's not in the right spot already. */ - pcb->rcv_sacks[unused_idx] = pcb->rcv_sacks[i]; - } - /* NOTE: It is possible that its left side is < 'seq', in which case we should adjust it. */ - if (TCP_SEQ_LT(pcb->rcv_sacks[unused_idx].left, seq)) { - pcb->rcv_sacks[unused_idx].left = seq; - } - ++unused_idx; - } - } - - /* We also need to invalidate everything from 'unused_idx' till the end */ - for (i = unused_idx; i < LWIP_TCP_MAX_SACK_NUM; ++i) { - pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; - } -} - -#if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) -/** - * Called to remove a range of SACKs. - * - * SACK entries will be removed or adjusted to not acknowledge any sequence - * numbers that are greater than (or equal to) 'seq' passed. It not only invalidates entries, - * but also moves all entries that are still valid to the beginning. - * - * @param pcb the tcp_pcb to modify - * @param seq the highest sequence number to keep in SACK entries - */ -static void -tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq) -{ - u8_t i; - u8_t unused_idx; - - /* We run this loop for all entries, until we find the first invalid one. - There is no point checking after that. */ - for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { - /* We only want to use SACK at index [i] if its left side is < 'seq'. */ - if (TCP_SEQ_LT(pcb->rcv_sacks[i].left, seq)) { - if (unused_idx != i) { - /* We only copy it if it's not in the right spot already. */ - pcb->rcv_sacks[unused_idx] = pcb->rcv_sacks[i]; - } - /* NOTE: It is possible that its right side is > 'seq', in which case we should adjust it. */ - if (TCP_SEQ_GT(pcb->rcv_sacks[unused_idx].right, seq)) { - pcb->rcv_sacks[unused_idx].right = seq; - } - ++unused_idx; - } - } - - /* We also need to invalidate everything from 'unused_idx' till the end */ - for (i = unused_idx; i < LWIP_TCP_MAX_SACK_NUM; ++i) { - pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; - } -} -#endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ - -#endif /* LWIP_TCP_SACK_OUT */ - -#endif /* LWIP_TCP */ diff --git a/core/c/core/tcp_out.c b/core/c/core/tcp_out.c deleted file mode 100755 index 375e18d..0000000 --- a/core/c/core/tcp_out.c +++ /dev/null @@ -1,2190 +0,0 @@ -/** - * @file - * Transmission Control Protocol, outgoing traffic - * - * The output functions of TCP. - * - * There are two distinct ways for TCP segments to get sent: - * - queued data: these are segments transferring data or segments containing - * SYN or FIN (which both count as one sequence number). They are created as - * struct @ref pbuf together with a struct tcp_seg and enqueue to the - * unsent list of the pcb. They are sent by tcp_output: - * - @ref tcp_write : creates data segments - * - @ref tcp_split_unsent_seg : splits a data segment - * - @ref tcp_enqueue_flags : creates SYN-only or FIN-only segments - * - @ref tcp_output / tcp_output_segment : finalize the tcp header - * (e.g. sequence numbers, options, checksum) and output to IP - * - the various tcp_rexmit functions shuffle around segments between the - * unsent an unacked lists to retransmit them - * - tcp_create_segment and tcp_pbuf_prealloc allocate pbuf and - * segment for these functions - * - direct send: these segments don't contain data but control the connection - * behaviour. They are created as pbuf only and sent directly without - * enqueueing them: - * - @ref tcp_send_empty_ack sends an ACK-only segment - * - @ref tcp_rst sends a RST segment - * - @ref tcp_keepalive sends a keepalive segment - * - @ref tcp_zero_window_probe sends a window probe segment - * - tcp_output_alloc_header allocates a header-only pbuf for these 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" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/priv/tcp_priv.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/inet_chksum.h" -#include "lwip/stats.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#if LWIP_TCP_TIMESTAMPS -#include "lwip/sys.h" -#endif - -#include - -#ifdef LWIP_HOOK_FILENAME -#include LWIP_HOOK_FILENAME -#endif - -/* Allow to add custom TCP header options by defining this hook */ -#ifdef LWIP_HOOK_TCP_OUT_TCPOPT_LENGTH -#define LWIP_TCP_OPT_LENGTH_SEGMENT(flags, pcb) LWIP_HOOK_TCP_OUT_TCPOPT_LENGTH(pcb, LWIP_TCP_OPT_LENGTH(flags)) -#else -#define LWIP_TCP_OPT_LENGTH_SEGMENT(flags, pcb) LWIP_TCP_OPT_LENGTH(flags) -#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 -/* Allow to override the failure of sanity check from warning to e.g. hard failure */ -#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK -#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL -#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL(msg) LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING, msg) -#endif -#endif - -#if TCP_OVERSIZE -/** The size of segment pbufs created when TCP_OVERSIZE is enabled */ -#ifndef TCP_OVERSIZE_CALC_LENGTH -#define TCP_OVERSIZE_CALC_LENGTH(length) ((length) + TCP_OVERSIZE) -#endif -#endif - -/* Forward declarations.*/ -static err_t tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif); - -/* tcp_route: common code that returns a fixed bound netif or calls ip_route */ -static struct netif * -tcp_route(const struct tcp_pcb *pcb, const ip_addr_t *src, const ip_addr_t *dst) -{ - LWIP_UNUSED_ARG(src); /* in case IPv4-only and source-based routing is disabled */ - - if ((pcb != NULL) && (pcb->netif_idx != NETIF_NO_INDEX)) { - return netif_get_by_index(pcb->netif_idx); - } else { - return ip_route(src, dst); - } -} - -/** - * Create a TCP segment with prefilled header. - * - * Called by @ref tcp_write, @ref tcp_enqueue_flags and @ref tcp_split_unsent_seg - * - * @param pcb Protocol control block for the TCP connection. - * @param p pbuf that is used to hold the TCP header. - * @param hdrflags 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 * -tcp_create_segment(const struct tcp_pcb *pcb, struct pbuf *p, u8_t hdrflags, u32_t seqno, u8_t optflags) -{ - struct tcp_seg *seg; - u8_t optlen; - - LWIP_ASSERT("tcp_create_segment: invalid pcb", pcb != NULL); - LWIP_ASSERT("tcp_create_segment: invalid pbuf", p != NULL); - - optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb); - - if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_create_segment: no memory.\n")); - pbuf_free(p); - return NULL; - } - seg->flags = optflags; - seg->next = NULL; - seg->p = p; - LWIP_ASSERT("p->tot_len >= optlen", p->tot_len >= optlen); - 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_add_header(p, TCP_HLEN)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("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 = lwip_htons(pcb->local_port); - seg->tcphdr->dest = lwip_htons(pcb->remote_port); - seg->tcphdr->seqno = lwip_htonl(seqno); - /* ackno is set in tcp_output */ - TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), hdrflags); - /* 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. - * - * Called by @ref tcp_write - * - * @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 will 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. - */ -#if TCP_OVERSIZE -static struct pbuf * -tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length, - u16_t *oversize, const struct tcp_pcb *pcb, u8_t apiflags, - u8_t first_seg) -{ - struct pbuf *p; - u16_t alloc = length; - - LWIP_ASSERT("tcp_pbuf_prealloc: invalid oversize", oversize != NULL); - LWIP_ASSERT("tcp_pbuf_prealloc: invalid pcb", pcb != NULL); - -#if LWIP_NETIF_TX_SINGLE_PBUF - LWIP_UNUSED_ARG(max_length); - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(apiflags); - LWIP_UNUSED_ARG(first_seg); - alloc = max_length; -#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(TCP_OVERSIZE_CALC_LENGTH(length))); - } - } -#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. - * - * Called by tcp_write and tcp_split_unsent_seg. - */ -static void -tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum, - u8_t *seg_chksum_swapped) -{ - u32_t helper; - /* add chksum to old chksum and fold to u16_t */ - helper = chksum + *seg_chksum; - chksum = FOLD_U32T(helper); - if ((len & 1) != 0) { - *seg_chksum_swapped = 1 - *seg_chksum_swapped; - chksum = SWAP_BYTES_IN_WORD(chksum); - } - *seg_chksum = chksum; -} -#endif /* TCP_CHECKSUM_ON_COPY */ - -/** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen). - * - * @param pcb the tcp pcb to check for - * @param len length of data to send (checked agains snd_buf) - * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise - */ -static err_t -tcp_write_checks(struct tcp_pcb *pcb, u16_t len) -{ - LWIP_ASSERT("tcp_write_checks: invalid pcb", pcb != NULL); - - /* connection is in invalid state for data transmission? */ - if ((pcb->state != ESTABLISHED) && - (pcb->state != CLOSE_WAIT) && - (pcb->state != SYN_SENT) && - (pcb->state != SYN_RCVD)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n")); - return ERR_CONN; - } else if (len == 0) { - return ERR_OK; - } - - /* fail on too much data */ - if (len > pcb->snd_buf) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"TCPWNDSIZE_F")\n", - len, pcb->snd_buf)); - tcp_set_flags(pcb, TF_NAGLEMEMERR); - return ERR_MEM; - } - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"TCPWNDSIZE_F"\n", (tcpwnd_size_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 >= LWIP_MIN(TCP_SND_QUEUELEN, (TCP_SNDQUEUELEN_OVERFLOW + 1))) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n", - pcb->snd_queuelen, (u16_t)TCP_SND_QUEUELEN)); - TCP_STATS_INC(tcp.memerr); - tcp_set_flags(pcb, 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; -} - -/** - * @ingroup tcp_raw - * 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(). - * - * This function enqueues the data pointed to by the argument dataptr. The length of - * the data is passed as the len parameter. The apiflags can be one or more of: - * - TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated - * for the data to be copied into. If this flag is not given, no new memory - * should be allocated and the data should only be referenced by pointer. This - * also means that the memory behind dataptr must not change until the data is - * ACKed by the remote host - * - TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is omitted, - * the PSH flag is set in the last segment created by this call to tcp_write. - * If this flag is given, the PSH flag is not set. - * - * The tcp_write() function will fail and return ERR_MEM if the length - * of the data exceeds the current send buffer size or if the length of - * the queue of outgoing segment is larger than the upper limit defined - * in lwipopts.h. The number of bytes available in the output queue can - * be retrieved with the tcp_sndbuf() function. - * - * The proper way to use this function is to call the function with at - * most tcp_sndbuf() bytes of data. If the function returns ERR_MEM, - * the application should wait until some of the currently enqueued - * data has been successfully received by the other host and try again. - * - * @param pcb Protocol control block for the TCP connection to enqueue data for. - * @param arg Pointer to the data to be enqueued for sending. - * @param len Data length in bytes - * @param apiflags combination of following flags : - * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack - * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will not 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; - u8_t optflags = 0; -#if TCP_OVERSIZE - u16_t oversize = 0; - u16_t oversize_used = 0; -#if TCP_OVERSIZE_DBGCHECK - u16_t oversize_add = 0; -#endif /* TCP_OVERSIZE_DBGCHECK*/ -#endif /* TCP_OVERSIZE */ - u16_t extendlen = 0; -#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; - u16_t mss_local; - - LWIP_ERROR("tcp_write: invalid pcb", pcb != NULL, return ERR_ARG); - - /* don't allocate segments bigger than half the maximum window we ever received */ - mss_local = LWIP_MIN(pcb->mss, TCPWND_MIN16(pcb->snd_wnd_max / 2)); - mss_local = mss_local ? mss_local : pcb->mss; - - LWIP_ASSERT_CORE_LOCKED(); - -#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)) { - /* Make sure the timestamp option is only included in data segments if we - agreed about it with the remote host. */ - optflags = TF_SEG_OPTS_TS; - optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(TF_SEG_OPTS_TS, pcb); - /* ensure that segments can hold at least one data byte... */ - mss_local = LWIP_MAX(mss_local, LWIP_TCP_OPT_LEN_TS + 1); - } else -#endif /* LWIP_TCP_TIMESTAMPS */ - { - optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb); - } - - - /* - * 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_SEGMENT(last_unsent->flags, pcb); - LWIP_ASSERT("mss_local is too small", mss_local >= last_unsent->len + unsent_optlen); - space = mss_local - (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->oversize_left */ - 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 <= space); - seg = last_unsent; - oversize_used = LWIP_MIN(space, LWIP_MIN(oversize, len)); - pos += oversize_used; - oversize -= oversize_used; - space -= oversize_used; - } - /* now we are either finished or oversize is zero */ - LWIP_ASSERT("inconsistent oversize vs. len", (oversize == 0) || (pos == len)); -#endif /* TCP_OVERSIZE */ - -#if !LWIP_NETIF_TX_SINGLE_PBUF - /* - * Phase 2: Chain a new pbuf to the end of pcb->unsent. - * - * As an exception when NOT copying the data, if the given data buffer - * directly follows the last unsent data buffer in memory, extend the last - * ROM pbuf reference to the buffer, thus saving a ROM pbuf allocation. - * - * 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. - * - * This phase is skipped for LWIP_NETIF_TX_SINGLE_PBUF as we could only execute - * it after rexmit puts a segment from unacked to unsent and at this point, - * oversize info is lost. - */ - if ((pos < len) && (space > 0) && (last_unsent->len > 0)) { - u16_t seglen = LWIP_MIN(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 | LWIP_DBG_LEVEL_SERIOUS, - ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", - seglen)); - goto memerr; - } -#if TCP_OVERSIZE_DBGCHECK - oversize_add = oversize; -#endif /* TCP_OVERSIZE_DBGCHECK */ - TCP_DATA_COPY2(concat_p->payload, (const u8_t *)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped); -#if TCP_CHECKSUM_ON_COPY - concat_chksummed += seglen; -#endif /* TCP_CHECKSUM_ON_COPY */ - queuelen += pbuf_clen(concat_p); - } else { - /* Data is not copied */ - /* If the last unsent pbuf is of type PBUF_ROM, try to extend it. */ - struct pbuf *p; - for (p = last_unsent->p; p->next != NULL; p = p->next); - if (((p->type_internal & (PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS | PBUF_TYPE_FLAG_DATA_VOLATILE)) == 0) && - (const u8_t *)p->payload + p->len == (const u8_t *)arg) { - LWIP_ASSERT("tcp_write: ROM pbufs cannot be oversized", pos == 0); - extendlen = seglen; - } else { - if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("tcp_write: could not allocate memory for zero-copy pbuf\n")); - goto memerr; - } - /* reference the non-volatile payload data */ - ((struct pbuf_rom *)concat_p)->payload = (const u8_t *)arg + pos; - queuelen += pbuf_clen(concat_p); - } -#if TCP_CHECKSUM_ON_COPY - /* calculate the checksum of nocopy-data */ - tcp_seg_add_chksum(~inet_chksum((const u8_t *)arg + pos, seglen), seglen, - &concat_chksum, &concat_chksum_swapped); - concat_chksummed += seglen; -#endif /* TCP_CHECKSUM_ON_COPY */ - } - - pos += seglen; - } -#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ - } 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 = mss_local - optlen; - u16_t seglen = LWIP_MIN(left, max_len); -#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, mss_local, &oversize, pcb, apiflags, queue == NULL)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("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, (const 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 | LWIP_DBG_LEVEL_SERIOUS, ("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((const u8_t *)arg + pos, seglen); - if (seglen & 1) { - chksum_swapped = 1; - chksum = SWAP_BYTES_IN_WORD(chksum); - } -#endif /* TCP_CHECKSUM_ON_COPY */ - /* reference the non-volatile payload data */ - ((struct pbuf_rom *)p2)->payload = (const 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 | LWIP_DBG_LEVEL_SERIOUS, ("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 > LWIP_MIN(TCP_SND_QUEUELEN, TCP_SNDQUEUELEN_OVERFLOW)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: queue too long %"U16_F" (%d)\n", - queuelen, (int)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", - lwip_ntohl(seg->tcphdr->seqno), - lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); - - pos += seglen; - } - - /* - * All three segmentation phases were successful. We can commit the - * transaction. - */ -#if TCP_OVERSIZE_DBGCHECK - if ((last_unsent != NULL) && (oversize_add != 0)) { - last_unsent->oversize_left += oversize_add; - } -#endif /* TCP_OVERSIZE_DBGCHECK */ - - /* - * 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 - LWIP_ASSERT("last_unsent->oversize_left >= oversize_used", - last_unsent->oversize_left >= oversize_used); - 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, unless we - * determined that the last ROM pbuf can be extended to include the new data. - */ - 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; - } else if (extendlen > 0) { - struct pbuf *p; - LWIP_ASSERT("tcp_write: extension of reference requires reference", - last_unsent != NULL && last_unsent->p != NULL); - for (p = last_unsent->p; p->next != NULL; p = p->next) { - p->tot_len += extendlen; - } - p->tot_len += extendlen; - p->len += extendlen; - last_unsent->len += extendlen; - } - -#if TCP_CHECKSUM_ON_COPY - if (concat_chksummed) { - LWIP_ASSERT("tcp_write: concat checksum needs concatenated data", - concat_p != NULL || extendlen > 0); - /*if concat checksumm swapped - swap it back */ - if (concat_chksum_swapped) { - concat_chksum = SWAP_BYTES_IN_WORD(concat_chksum); - } - 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: - tcp_set_flags(pcb, 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; -} - -/** - * Split segment on the head of the unsent queue. If return is not - * ERR_OK, existing head remains intact - * - * The split is accomplished by creating a new TCP segment and pbuf - * which holds the remainder payload after the split. The original - * pbuf is trimmed to new length. This allows splitting of read-only - * pbufs - * - * @param pcb the tcp_pcb for which to split the unsent head - * @param split the amount of payload to remain in the head - */ -err_t -tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t split) -{ - struct tcp_seg *seg = NULL, *useg = NULL; - struct pbuf *p = NULL; - u8_t optlen; - u8_t optflags; - u8_t split_flags; - u8_t remainder_flags; - u16_t remainder; - u16_t offset; -#if TCP_CHECKSUM_ON_COPY - u16_t chksum = 0; - u8_t chksum_swapped = 0; - struct pbuf *q; -#endif /* TCP_CHECKSUM_ON_COPY */ - - LWIP_ASSERT("tcp_split_unsent_seg: invalid pcb", pcb != NULL); - - useg = pcb->unsent; - if (useg == NULL) { - return ERR_MEM; - } - - if (split == 0) { - LWIP_ASSERT("Can't split segment into length 0", 0); - return ERR_VAL; - } - - if (useg->len <= split) { - return ERR_OK; - } - - LWIP_ASSERT("split <= mss", split <= pcb->mss); - LWIP_ASSERT("useg->len > 0", useg->len > 0); - - /* We should check that we don't exceed TCP_SND_QUEUELEN but we need - * to split this packet so we may actually exceed the max value by - * one! - */ - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: split_unsent_seg: %u\n", (unsigned int)pcb->snd_queuelen)); - - optflags = useg->flags; -#if TCP_CHECKSUM_ON_COPY - /* Remove since checksum is not stored until after tcp_create_segment() */ - optflags &= ~TF_SEG_DATA_CHECKSUMMED; -#endif /* TCP_CHECKSUM_ON_COPY */ - optlen = LWIP_TCP_OPT_LENGTH(optflags); - remainder = useg->len - split; - - /* Create new pbuf for the remainder of the split */ - p = pbuf_alloc(PBUF_TRANSPORT, remainder + optlen, PBUF_RAM); - if (p == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("tcp_split_unsent_seg: could not allocate memory for pbuf remainder %u\n", remainder)); - goto memerr; - } - - /* Offset into the original pbuf is past TCP/IP headers, options, and split amount */ - offset = useg->p->tot_len - useg->len + split; - /* Copy remainder into new pbuf, headers and options will not be filled out */ - if (pbuf_copy_partial(useg->p, (u8_t *)p->payload + optlen, remainder, offset ) != remainder) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("tcp_split_unsent_seg: could not copy pbuf remainder %u\n", remainder)); - goto memerr; - } -#if TCP_CHECKSUM_ON_COPY - /* calculate the checksum on remainder data */ - tcp_seg_add_chksum(~inet_chksum((const u8_t *)p->payload + optlen, remainder), remainder, - &chksum, &chksum_swapped); -#endif /* TCP_CHECKSUM_ON_COPY */ - - /* Options are created when calling tcp_output() */ - - /* Migrate flags from original segment */ - split_flags = TCPH_FLAGS(useg->tcphdr); - remainder_flags = 0; /* ACK added in tcp_output() */ - - if (split_flags & TCP_PSH) { - split_flags &= ~TCP_PSH; - remainder_flags |= TCP_PSH; - } - if (split_flags & TCP_FIN) { - split_flags &= ~TCP_FIN; - remainder_flags |= TCP_FIN; - } - /* SYN should be left on split, RST should not be present with data */ - - seg = tcp_create_segment(pcb, p, remainder_flags, lwip_ntohl(useg->tcphdr->seqno) + split, optflags); - if (seg == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("tcp_split_unsent_seg: could not create new TCP segment\n")); - goto memerr; - } - -#if TCP_CHECKSUM_ON_COPY - seg->chksum = chksum; - seg->chksum_swapped = chksum_swapped; - seg->flags |= TF_SEG_DATA_CHECKSUMMED; -#endif /* TCP_CHECKSUM_ON_COPY */ - - /* Remove this segment from the queue since trimming it may free pbufs */ - pcb->snd_queuelen -= pbuf_clen(useg->p); - - /* Trim the original pbuf into our split size. At this point our remainder segment must be setup - successfully because we are modifying the original segment */ - pbuf_realloc(useg->p, useg->p->tot_len - remainder); - useg->len -= remainder; - TCPH_SET_FLAG(useg->tcphdr, split_flags); -#if TCP_OVERSIZE_DBGCHECK - /* By trimming, realloc may have actually shrunk the pbuf, so clear oversize_left */ - useg->oversize_left = 0; -#endif /* TCP_OVERSIZE_DBGCHECK */ - - /* Add back to the queue with new trimmed pbuf */ - pcb->snd_queuelen += pbuf_clen(useg->p); - -#if TCP_CHECKSUM_ON_COPY - /* The checksum on the split segment is now incorrect. We need to re-run it over the split */ - useg->chksum = 0; - useg->chksum_swapped = 0; - q = useg->p; - offset = q->tot_len - useg->len; /* Offset due to exposed headers */ - - /* Advance to the pbuf where the offset ends */ - while (q != NULL && offset > q->len) { - offset -= q->len; - q = q->next; - } - LWIP_ASSERT("Found start of payload pbuf", q != NULL); - /* Checksum the first payload pbuf accounting for offset, then other pbufs are all payload */ - for (; q != NULL; offset = 0, q = q->next) { - tcp_seg_add_chksum(~inet_chksum((const u8_t *)q->payload + offset, q->len - offset), q->len - offset, - &useg->chksum, &useg->chksum_swapped); - } -#endif /* TCP_CHECKSUM_ON_COPY */ - - /* Update number of segments on the queues. Note that length now may - * exceed TCP_SND_QUEUELEN! We don't have to touch pcb->snd_buf - * because the total amount of data is constant when packet is split */ - pcb->snd_queuelen += pbuf_clen(seg->p); - - /* Finally insert remainder into queue after split (which stays head) */ - seg->next = useg->next; - useg->next = seg; - -#if TCP_OVERSIZE - /* If remainder is last segment on the unsent, ensure we clear the oversize amount - * because the remainder is always sized to the exact remaining amount */ - if (seg->next == NULL) { - pcb->unsent_oversize = 0; - } -#endif /* TCP_OVERSIZE */ - - return ERR_OK; -memerr: - TCP_STATS_INC(tcp.memerr); - - LWIP_ASSERT("seg == NULL", seg == NULL); - if (p != NULL) { - pbuf_free(p); - } - - return ERR_MEM; -} - -/** - * Called by tcp_close() to send a segment including FIN flag but not data. - * This FIN may be added to an existing segment or a new, otherwise empty - * segment is enqueued. - * - * @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) -{ - LWIP_ASSERT("tcp_send_fin: invalid pcb", pcb != NULL); - - /* 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); - tcp_set_flags(pcb, TF_FIN); - return ERR_OK; - } - } - /* no data, no length, flags, copy=1, no optdata */ - return tcp_enqueue_flags(pcb, TCP_FIN); -} - -/** - * Enqueue SYN or FIN for transmission. - * - * Called by @ref tcp_connect, tcp_listen_input, and @ref tcp_close - * (via @ref tcp_send_fin) - * - * @param pcb Protocol control block for the TCP connection. - * @param flags TCP header flags to set in the outgoing segment. - */ -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); - LWIP_ASSERT("tcp_enqueue_flags: invalid pcb", pcb != NULL); - - /* No need to check pcb->snd_queuelen if only SYN or FIN are allowed! */ - - /* Get options for this segment. This is a special case since this is the - only place where a SYN can be sent. */ - if (flags & TCP_SYN) { - optflags = TF_SEG_OPTS_MSS; -#if LWIP_WND_SCALE - if ((pcb->state != SYN_RCVD) || (pcb->flags & TF_WND_SCALE)) { - /* In a (sent in state SYN_RCVD), the window scale option may only - be sent if we received a window scale option from the remote host. */ - optflags |= TF_SEG_OPTS_WND_SCALE; - } -#endif /* LWIP_WND_SCALE */ -#if LWIP_TCP_SACK_OUT - if ((pcb->state != SYN_RCVD) || (pcb->flags & TF_SACK)) { - /* In a (sent in state SYN_RCVD), the SACK_PERM option may only - be sent if we received a SACK_PERM option from the remote host. */ - optflags |= TF_SEG_OPTS_SACK_PERM; - } -#endif /* LWIP_TCP_SACK_OUT */ - } -#if LWIP_TCP_TIMESTAMPS - if ((pcb->flags & TF_TIMESTAMP) || ((flags & TCP_SYN) && (pcb->state != SYN_RCVD))) { - /* Make sure the timestamp option is only included in data segments if we - agreed about it with the remote host (and in active open SYN segments). */ - optflags |= TF_SEG_OPTS_TS; - } -#endif /* LWIP_TCP_TIMESTAMPS */ - optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb); - - /* Allocate pbuf with room for TCP header + options */ - if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { - tcp_set_flags(pcb, 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) { - tcp_set_flags(pcb, TF_NAGLEMEMERR); - TCP_STATS_INC(tcp.memerr); - return ERR_MEM; - } - LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % LWIP_MIN(MEM_ALIGNMENT, 4)) == 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", - lwip_ntohl(seg->tcphdr->seqno), - lwip_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 */ - } - if (flags & TCP_FIN) { - tcp_set_flags(pcb, 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 -tcp_build_timestamp_option(const struct tcp_pcb *pcb, u32_t *opts) -{ - LWIP_ASSERT("tcp_build_timestamp_option: invalid pcb", pcb != NULL); - - /* Pad with two NOP options to make everything nicely aligned */ - opts[0] = PP_HTONL(0x0101080A); - opts[1] = lwip_htonl(sys_now()); - opts[2] = lwip_htonl(pcb->ts_recent); -} -#endif - -#if LWIP_TCP_SACK_OUT -/** - * Calculates the number of SACK entries that should be generated. - * It takes into account whether TF_SACK flag is set, - * the number of SACK entries in tcp_pcb that are valid, - * as well as the available options size. - * - * @param pcb tcp_pcb - * @param optlen the length of other TCP options (in bytes) - * @return the number of SACK ranges that can be used - */ -static u8_t -tcp_get_num_sacks(const struct tcp_pcb *pcb, u8_t optlen) -{ - u8_t num_sacks = 0; - - LWIP_ASSERT("tcp_get_num_sacks: invalid pcb", pcb != NULL); - - if (pcb->flags & TF_SACK) { - u8_t i; - - /* The first SACK takes up 12 bytes (it includes SACK header and two NOP options), - each additional one - 8 bytes. */ - optlen += 12; - - /* Max options size = 40, number of SACK array entries = LWIP_TCP_MAX_SACK_NUM */ - for (i = 0; (i < LWIP_TCP_MAX_SACK_NUM) && (optlen <= TCP_MAX_OPTION_BYTES) && - LWIP_TCP_SACK_VALID(pcb, i); ++i) { - ++num_sacks; - optlen += 8; - } - } - - return num_sacks; -} - -/** Build a SACK option (12 or more bytes long) at the specified options pointer) - * - * @param pcb tcp_pcb - * @param opts option pointer where to store the SACK option - * @param num_sacks the number of SACKs to store - */ -static void -tcp_build_sack_option(const struct tcp_pcb *pcb, u32_t *opts, u8_t num_sacks) -{ - u8_t i; - - LWIP_ASSERT("tcp_build_sack_option: invalid pcb", pcb != NULL); - LWIP_ASSERT("tcp_build_sack_option: invalid opts", opts != NULL); - - /* Pad with two NOP options to make everything nicely aligned. - We add the length (of just the SACK option, not the NOPs in front of it), - which is 2B of header, plus 8B for each SACK. */ - *(opts++) = PP_HTONL(0x01010500 + 2 + num_sacks * 8); - - for (i = 0; i < num_sacks; ++i) { - *(opts++) = lwip_htonl(pcb->rcv_sacks[i].left); - *(opts++) = lwip_htonl(pcb->rcv_sacks[i].right); - } -} - -#endif - -#if LWIP_WND_SCALE -/** Build a window scale option (3 bytes long) at the specified options pointer) - * - * @param opts option pointer where to store the window scale option - */ -static void -tcp_build_wnd_scale_option(u32_t *opts) -{ - LWIP_ASSERT("tcp_build_wnd_scale_option: invalid opts", opts != NULL); - - /* Pad with one NOP option to make everything nicely aligned */ - opts[0] = PP_HTONL(0x01030300 | TCP_RCV_SCALE); -} -#endif - -/** - * @ingroup tcp_raw - * 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 -tcp_output(struct tcp_pcb *pcb) -{ - struct tcp_seg *seg, *useg; - u32_t wnd, snd_nxt; - err_t err; - struct netif *netif; -#if TCP_CWND_DEBUG - s16_t i = 0; -#endif /* TCP_CWND_DEBUG */ - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ASSERT("tcp_output: invalid pcb", pcb != NULL); - /* pcb->state LISTEN not allowed here */ - LWIP_ASSERT("don't call tcp_output for listen-pcbs", - pcb->state != LISTEN); - - /* 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 (seg == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", - (void *)pcb->unsent)); - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F - ", cwnd %"TCPWNDSIZE_F", wnd %"U32_F - ", seg == NULL, ack %"U32_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack)); - - /* If the TF_ACK_NOW flag is set and the ->unsent queue is empty, construct - * an empty ACK segment and send it. */ - if (pcb->flags & TF_ACK_NOW) { - return tcp_send_empty_ack(pcb); - } - /* nothing to send: shortcut out of here */ - goto output_done; - } else { - LWIP_DEBUGF(TCP_CWND_DEBUG, - ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F - ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, - lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len, - lwip_ntohl(seg->tcphdr->seqno), pcb->lastack)); - } - - netif = tcp_route(pcb, &pcb->local_ip, &pcb->remote_ip); - if (netif == NULL) { - return ERR_RTE; - } - - /* If we don't have a local IP address, we get one from netif */ - if (ip_addr_isany(&pcb->local_ip)) { - const ip_addr_t *local_ip = ip_netif_get_local_ip(netif, &pcb->remote_ip); - if (local_ip == NULL) { - return ERR_RTE; - } - ip_addr_copy(pcb->local_ip, *local_ip); - } - - /* Handle the current segment not fitting within the window */ - if (lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd) { - /* We need to start the persistent timer when the next unsent segment does not fit - * within the remaining (could be 0) send window and RTO timer is not running (we - * have no in-flight data). If window is still too small after persist timer fires, - * then we split the segment. We don't consider the congestion window since a cwnd - * smaller than 1 SMSS implies in-flight data - */ - if (wnd == pcb->snd_wnd && pcb->unacked == NULL && pcb->persist_backoff == 0) { - pcb->persist_cnt = 0; - pcb->persist_backoff = 1; - pcb->persist_probe = 0; - } - /* We need an ACK, but can't send data now, so send an empty ACK */ - if (pcb->flags & TF_ACK_NOW) { - return tcp_send_empty_ack(pcb); - } - goto output_done; - } - /* Stop persist timer, above conditions are not active */ - pcb->persist_backoff = 0; - - /* useg should point to last segment on unacked queue */ - useg = pcb->unacked; - if (useg != NULL) { - for (; useg->next != NULL; useg = useg->next); - } - /* data available and window allows it to be sent? */ - while (seg != NULL && - lwip_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 %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, - lwip_ntohl(seg->tcphdr->seqno) + seg->len - - pcb->lastack, - lwip_ntohl(seg->tcphdr->seqno), pcb->lastack, i)); - ++i; -#endif /* TCP_CWND_DEBUG */ - - if (pcb->state != SYN_SENT) { - TCPH_SET_FLAG(seg->tcphdr, TCP_ACK); - } - - err = tcp_output_segment(seg, pcb, netif); - if (err != ERR_OK) { - /* segment could not be sent, for whatever reason */ - tcp_set_flags(pcb, TF_NAGLEMEMERR); - return err; - } -#if TCP_OVERSIZE_DBGCHECK - seg->oversize_left = 0; -#endif /* TCP_OVERSIZE_DBGCHECK */ - pcb->unsent = seg->next; - if (pcb->state != SYN_SENT) { - tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); - } - snd_nxt = lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); - 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(lwip_ntohl(seg->tcphdr->seqno), lwip_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(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_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 { - 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 */ - -output_done: - tcp_clear_flags(pcb, TF_NAGLEMEMERR); - return ERR_OK; -} - -/** Check if a segment's pbufs are used by someone else than TCP. - * This can happen on retransmission if the pbuf of this segment is still - * referenced by the netif driver due to deferred transmission. - * This is the case (only!) if someone down the TX call path called - * pbuf_ref() on one of the pbufs! - * - * @arg seg the tcp segment to check - * @return 1 if ref != 1, 0 if ref == 1 - */ -static int -tcp_output_segment_busy(const struct tcp_seg *seg) -{ - LWIP_ASSERT("tcp_output_segment_busy: invalid seg", seg != NULL); - - /* We only need to check the first pbuf here: - If a pbuf is queued for transmission, a driver calls pbuf_ref(), - which only changes the ref count of the first pbuf */ - if (seg->p->ref != 1) { - /* other reference found */ - return 1; - } - /* no other references found */ - return 0; -} - -/** - * 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 - * @param netif the netif used to send the segment - */ -static err_t -tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif) -{ - err_t err; - u16_t len; - u32_t *opts; -#if TCP_CHECKSUM_ON_COPY - int seg_chksum_was_swapped = 0; -#endif - - LWIP_ASSERT("tcp_output_segment: invalid seg", seg != NULL); - LWIP_ASSERT("tcp_output_segment: invalid pcb", pcb != NULL); - LWIP_ASSERT("tcp_output_segment: invalid netif", netif != NULL); - - if (tcp_output_segment_busy(seg)) { - /* This should not happen: rexmit functions should have checked this. - However, since this function modifies p->len, we must not continue in this case. */ - LWIP_DEBUGF(TCP_RTO_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_output_segment: segment busy\n")); - return ERR_OK; - } - - /* The TCP header has already been constructed, but the ackno and - wnd fields remain. */ - seg->tcphdr->ackno = lwip_htonl(pcb->rcv_nxt); - - /* advertise our receive window size in this TCP segment */ -#if LWIP_WND_SCALE - if (seg->flags & TF_SEG_OPTS_WND_SCALE) { - /* The Window field in a SYN segment itself (the only type where we send - the window scale option) is never scaled. */ - seg->tcphdr->wnd = lwip_htons(TCPWND_MIN16(pcb->rcv_ann_wnd)); - } else -#endif /* LWIP_WND_SCALE */ - { - seg->tcphdr->wnd = lwip_htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, 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 */ - /* cast through void* to get rid of alignment warnings */ - opts = (u32_t *)(void *)(seg->tcphdr + 1); - if (seg->flags & TF_SEG_OPTS_MSS) { - u16_t mss; -#if TCP_CALCULATE_EFF_SEND_MSS - mss = tcp_eff_send_mss_netif(TCP_MSS, netif, &pcb->remote_ip); -#else /* TCP_CALCULATE_EFF_SEND_MSS */ - mss = TCP_MSS; -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - *opts = TCP_BUILD_MSS_OPTION(mss); - 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 -#if LWIP_WND_SCALE - if (seg->flags & TF_SEG_OPTS_WND_SCALE) { - tcp_build_wnd_scale_option(opts); - opts += 1; - } -#endif -#if LWIP_TCP_SACK_OUT - if (seg->flags & TF_SEG_OPTS_SACK_PERM) { - /* Pad with two NOP options to make everything nicely aligned - * NOTE: When we send both timestamp and SACK_PERM options, - * we could use the first two NOPs before the timestamp to store SACK_PERM option, - * but that would complicate the code. - */ - *(opts++) = PP_HTONL(0x01010402); - } -#endif - - /* Set retransmission timer running if it is not currently enabled - This must be set before checking the route. */ - if (pcb->rtime < 0) { - pcb->rtime = 0; - } - - if (pcb->rttest == 0) { - pcb->rttest = tcp_ticks; - pcb->rtseq = lwip_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", - lwip_htonl(seg->tcphdr->seqno), lwip_htonl(seg->tcphdr->seqno) + - seg->len)); - - len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload); - if (len == 0) { - /** Exclude retransmitted segments from this count. */ - MIB2_STATS_INC(mib2.tcpoutsegs); - } - - seg->p->len -= len; - seg->p->tot_len -= len; - - seg->p->payload = seg->tcphdr; - - seg->tcphdr->chksum = 0; - -#ifdef LWIP_HOOK_TCP_OUT_ADD_TCPOPTS - opts = LWIP_HOOK_TCP_OUT_ADD_TCPOPTS(seg->p, seg->tcphdr, pcb, opts); -#endif - LWIP_ASSERT("options not filled", (u8_t *)opts == ((u8_t *)(seg->tcphdr + 1)) + LWIP_TCP_OPT_LENGTH_SEGMENT(seg->flags, pcb)); - -#if CHECKSUM_GEN_TCP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { -#if TCP_CHECKSUM_ON_COPY - u32_t acc; -#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK - u16_t chksum_slow = ip_chksum_pseudo(seg->p, IP_PROTO_TCP, - seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); -#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_BYTES(seg->tcphdr)); - } - - /* rebuild TCP header checksum (TCP header changes for retransmissions!) */ - acc = ip_chksum_pseudo_partial(seg->p, IP_PROTO_TCP, - seg->p->tot_len, TCPH_HDRLEN_BYTES(seg->tcphdr), &pcb->local_ip, &pcb->remote_ip); - /* add payload checksum */ - if (seg->chksum_swapped) { - seg_chksum_was_swapped = 1; - seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); - seg->chksum_swapped = 0; - } - acc = (u16_t)~acc + seg->chksum; - seg->tcphdr->chksum = (u16_t)~FOLD_U32T(acc); -#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK - if (chksum_slow != seg->tcphdr->chksum) { - TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL( - ("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 = ip_chksum_pseudo(seg->p, IP_PROTO_TCP, - seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); -#endif /* TCP_CHECKSUM_ON_COPY */ - } -#endif /* CHECKSUM_GEN_TCP */ - TCP_STATS_INC(tcp.xmit); - - NETIF_SET_HINTS(netif, &(pcb->netif_hints)); - err = ip_output_if(seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, - pcb->tos, IP_PROTO_TCP, netif); - NETIF_RESET_HINTS(netif); - -#if TCP_CHECKSUM_ON_COPY - if (seg_chksum_was_swapped) { - /* if data is added to this segment later, chksum needs to be swapped, - so restore this now */ - seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); - seg->chksum_swapped = 1; - } -#endif - - return err; -} - -/** - * 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 - */ -err_t -tcp_rexmit_rto_prepare(struct tcp_pcb *pcb) -{ - struct tcp_seg *seg; - - LWIP_ASSERT("tcp_rexmit_rto_prepare: invalid pcb", pcb != NULL); - - if (pcb->unacked == NULL) { - return ERR_VAL; - } - - /* Move all unacked segments to the head of the unsent queue. - However, give up if any of the unsent pbufs are still referenced by the - netif driver due to deferred transmission. No point loading the link further - if it is struggling to flush its buffered writes. */ - for (seg = pcb->unacked; seg->next != NULL; seg = seg->next) { - if (tcp_output_segment_busy(seg)) { - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit_rto: segment busy\n")); - return ERR_VAL; - } - } - if (tcp_output_segment_busy(seg)) { - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit_rto: segment busy\n")); - return ERR_VAL; - } - /* concatenate unsent queue after unacked queue */ - seg->next = pcb->unsent; -#if TCP_OVERSIZE_DBGCHECK - /* if last unsent changed, we need to update unsent_oversize */ - if (pcb->unsent == NULL) { - pcb->unsent_oversize = seg->oversize_left; - } -#endif /* TCP_OVERSIZE_DBGCHECK */ - /* unsent queue is the concatenated queue (of unacked, unsent) */ - pcb->unsent = pcb->unacked; - /* unacked queue is now empty */ - pcb->unacked = NULL; - - /* Mark RTO in-progress */ - tcp_set_flags(pcb, TF_RTO); - /* Record the next byte following retransmit */ - pcb->rto_end = lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); - /* Don't take any RTT measurements after retransmitting. */ - pcb->rttest = 0; - - return ERR_OK; -} - -/** - * 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_commit(struct tcp_pcb *pcb) -{ - LWIP_ASSERT("tcp_rexmit_rto_commit: invalid pcb", pcb != NULL); - - /* increment number of retransmissions */ - if (pcb->nrtx < 0xFF) { - ++pcb->nrtx; - } - /* Do the actual retransmission */ - tcp_output(pcb); -} - -/** - * Requeue all unacked segments for retransmission - * - * Called by tcp_process() only, tcp_slowtmr() needs to do some things between - * "prepare" and "commit". - * - * @param pcb the tcp_pcb for which to re-enqueue all unacked segments - */ -void -tcp_rexmit_rto(struct tcp_pcb *pcb) -{ - LWIP_ASSERT("tcp_rexmit_rto: invalid pcb", pcb != NULL); - - if (tcp_rexmit_rto_prepare(pcb) == ERR_OK) { - tcp_rexmit_rto_commit(pcb); - } -} - -/** - * Requeue the first unacked segment for retransmission - * - * Called by tcp_receive() for fast retransmit. - * - * @param pcb the tcp_pcb for which to retransmit the first unacked segment - */ -err_t -tcp_rexmit(struct tcp_pcb *pcb) -{ - struct tcp_seg *seg; - struct tcp_seg **cur_seg; - - LWIP_ASSERT("tcp_rexmit: invalid pcb", pcb != NULL); - - if (pcb->unacked == NULL) { - return ERR_VAL; - } - - seg = pcb->unacked; - - /* Give up if the segment is still referenced by the netif driver - due to deferred transmission. */ - if (tcp_output_segment_busy(seg)) { - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit busy\n")); - return ERR_VAL; - } - - /* Move the first unacked segment to the unsent queue */ - /* Keep the unsent queue sorted. */ - pcb->unacked = seg->next; - - cur_seg = &(pcb->unsent); - while (*cur_seg && - TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) { - cur_seg = &((*cur_seg)->next ); - } - seg->next = *cur_seg; - *cur_seg = seg; -#if TCP_OVERSIZE - if (seg->next == NULL) { - /* the retransmitted segment is last in unsent, so reset unsent_oversize */ - pcb->unsent_oversize = 0; - } -#endif /* TCP_OVERSIZE */ - - if (pcb->nrtx < 0xFF) { - ++pcb->nrtx; - } - - /* Don't take any rtt measurements after retransmitting. */ - pcb->rttest = 0; - - /* Do the actual retransmission. */ - MIB2_STATS_INC(mib2.tcpretranssegs); - /* No need to call tcp_output: we are always called from tcp_input() - and thus tcp_output directly returns. */ - return ERR_OK; -} - - -/** - * 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) -{ - LWIP_ASSERT("tcp_rexmit_fast: invalid pcb", pcb != NULL); - - 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, - lwip_ntohl(pcb->unacked->tcphdr->seqno))); - if (tcp_rexmit(pcb) == ERR_OK) { - /* Set ssthresh to half of the minimum of the current - * cwnd and the advertised window */ - pcb->ssthresh = LWIP_MIN(pcb->cwnd, pcb->snd_wnd) / 2; - - /* The minimum value for ssthresh should be 2 MSS */ - if (pcb->ssthresh < (2U * pcb->mss)) { - LWIP_DEBUGF(TCP_FR_DEBUG, - ("tcp_receive: The minimum value for ssthresh %"TCPWNDSIZE_F - " should be min 2 mss %"U16_F"...\n", - pcb->ssthresh, (u16_t)(2 * pcb->mss))); - pcb->ssthresh = 2 * pcb->mss; - } - - pcb->cwnd = pcb->ssthresh + 3 * pcb->mss; - tcp_set_flags(pcb, TF_INFR); - - /* Reset the retransmission timer to prevent immediate rto retransmissions */ - pcb->rtime = 0; - } - } -} - -static struct pbuf * -tcp_output_alloc_header_common(u32_t ackno, u16_t optlen, u16_t datalen, - u32_t seqno_be /* already in network byte order */, - u16_t src_port, u16_t dst_port, u8_t flags, u16_t wnd) -{ - struct tcp_hdr *tcphdr; - struct pbuf *p; - - 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 = lwip_htons(src_port); - tcphdr->dest = lwip_htons(dst_port); - tcphdr->seqno = seqno_be; - tcphdr->ackno = lwip_htonl(ackno); - TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), flags); - tcphdr->wnd = lwip_htons(wnd); - tcphdr->chksum = 0; - tcphdr->urgp = 0; - } - return p; -} - -/** Allocate a pbuf and create a tcphdr at p->payload, used for output - * functions other than the default tcp_output -> tcp_output_segment - * (e.g. tcp_send_empty_ack, etc.) - * - * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr) - * @param optlen length of header-options - * @param datalen length of tcp data to reserve in pbuf - * @param seqno_be seqno in network byte order (big-endian) - * @return pbuf with p->payload being the tcp_hdr - */ -static struct pbuf * -tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen, - u32_t seqno_be /* already in network byte order */) -{ - struct pbuf *p; - - LWIP_ASSERT("tcp_output_alloc_header: invalid pcb", pcb != NULL); - - p = tcp_output_alloc_header_common(pcb->rcv_nxt, optlen, datalen, - seqno_be, pcb->local_port, pcb->remote_port, TCP_ACK, - TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd))); - if (p != NULL) { - /* 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; -} - -/* Fill in options for control segments */ -static void -tcp_output_fill_options(const struct tcp_pcb *pcb, struct pbuf *p, u8_t optflags, u8_t num_sacks) -{ - struct tcp_hdr *tcphdr; - u32_t *opts; - u16_t sacks_len = 0; - - LWIP_ASSERT("tcp_output_fill_options: invalid pbuf", p != NULL); - - tcphdr = (struct tcp_hdr *)p->payload; - opts = (u32_t *)(void *)(tcphdr + 1); - - /* NB. MSS and window scale options are only sent on SYNs, so ignore them here */ - -#if LWIP_TCP_TIMESTAMPS - if (optflags & TF_SEG_OPTS_TS) { - tcp_build_timestamp_option(pcb, opts); - opts += 3; - } -#endif - -#if LWIP_TCP_SACK_OUT - if (pcb && (num_sacks > 0)) { - tcp_build_sack_option(pcb, opts, num_sacks); - /* 1 word for SACKs header (including 2xNOP), and 2 words for each SACK */ - sacks_len = 1 + num_sacks * 2; - opts += sacks_len; - } -#else - LWIP_UNUSED_ARG(num_sacks); -#endif - -#ifdef LWIP_HOOK_TCP_OUT_ADD_TCPOPTS - opts = LWIP_HOOK_TCP_OUT_ADD_TCPOPTS(p, tcphdr, pcb, opts); -#endif - - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(sacks_len); - LWIP_ASSERT("options not filled", (u8_t *)opts == ((u8_t *)(tcphdr + 1)) + sacks_len * 4 + LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb)); - LWIP_UNUSED_ARG(optflags); /* for LWIP_NOASSERT */ - LWIP_UNUSED_ARG(opts); /* for LWIP_NOASSERT */ -} - -/** Output a control segment pbuf to IP. - * - * Called from tcp_rst, tcp_send_empty_ack, tcp_keepalive and tcp_zero_window_probe, - * this function combines selecting a netif for transmission, generating the tcp - * header checksum and calling ip_output_if while handling netif hints and stats. - */ -static err_t -tcp_output_control_segment(const struct tcp_pcb *pcb, struct pbuf *p, - const ip_addr_t *src, const ip_addr_t *dst) -{ - err_t err; - struct netif *netif; - - LWIP_ASSERT("tcp_output_control_segment: invalid pbuf", p != NULL); - - netif = tcp_route(pcb, src, dst); - if (netif == NULL) { - err = ERR_RTE; - } else { - u8_t ttl, tos; -#if CHECKSUM_GEN_TCP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { - struct tcp_hdr *tcphdr = (struct tcp_hdr *)p->payload; - tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - src, dst); - } -#endif - if (pcb != NULL) { - NETIF_SET_HINTS(netif, LWIP_CONST_CAST(struct netif_hint*, &(pcb->netif_hints))); - ttl = pcb->ttl; - tos = pcb->tos; - } else { - /* Send output with hardcoded TTL/HL since we have no access to the pcb */ - ttl = TCP_TTL; - tos = 0; - } - TCP_STATS_INC(tcp.xmit); - err = ip_output_if(p, src, dst, ttl, tos, IP_PROTO_TCP, netif); - NETIF_RESET_HINTS(netif); - } - pbuf_free(p); - return err; -} - -/** - * 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 pcb TCP pcb (may be NULL if no pcb is available) - * @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(const struct tcp_pcb *pcb, u32_t seqno, u32_t ackno, - const ip_addr_t *local_ip, const ip_addr_t *remote_ip, - u16_t local_port, u16_t remote_port) -{ - struct pbuf *p; - u16_t wnd; - u8_t optlen; - - LWIP_ASSERT("tcp_rst: invalid local_ip", local_ip != NULL); - LWIP_ASSERT("tcp_rst: invalid remote_ip", remote_ip != NULL); - - optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb); - -#if LWIP_WND_SCALE - wnd = PP_HTONS(((TCP_WND >> TCP_RCV_SCALE) & 0xFFFF)); -#else - wnd = PP_HTONS(TCP_WND); -#endif - - p = tcp_output_alloc_header_common(ackno, optlen, 0, lwip_htonl(seqno), local_port, - remote_port, TCP_RST | TCP_ACK, wnd); - if (p == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); - return; - } - tcp_output_fill_options(pcb, p, 0, optlen); - - MIB2_STATS_INC(mib2.tcpoutrsts); - - tcp_output_control_segment(pcb, p, local_ip, remote_ip); - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); -} - -/** - * 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) -{ - err_t err; - struct pbuf *p; - u8_t optlen, optflags = 0; - u8_t num_sacks = 0; - - LWIP_ASSERT("tcp_send_empty_ack: invalid pcb", pcb != NULL); - -#if LWIP_TCP_TIMESTAMPS - if (pcb->flags & TF_TIMESTAMP) { - optflags = TF_SEG_OPTS_TS; - } -#endif - optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb); - -#if LWIP_TCP_SACK_OUT - /* For now, SACKs are only sent with empty ACKs */ - if ((num_sacks = tcp_get_num_sacks(pcb, optlen)) > 0) { - optlen += 4 + num_sacks * 8; /* 4 bytes for header (including 2*NOP), plus 8B for each SACK */ - } -#endif - - p = tcp_output_alloc_header(pcb, optlen, 0, lwip_htonl(pcb->snd_nxt)); - if (p == NULL) { - /* let tcp_fasttmr retry sending this ACK */ - tcp_set_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); - return ERR_BUF; - } - tcp_output_fill_options(pcb, p, optflags, num_sacks); - -#if LWIP_TCP_TIMESTAMPS - pcb->ts_lastacksent = pcb->rcv_nxt; -#endif - - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, - ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); - err = tcp_output_control_segment(pcb, p, &pcb->local_ip, &pcb->remote_ip); - if (err != ERR_OK) { - /* let tcp_fasttmr retry sending this ACK */ - tcp_set_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); - } else { - /* remove ACK flags from the PCB, as we sent an empty ACK now */ - tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); - } - - return err; -} - -/** - * 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 - */ -err_t -tcp_keepalive(struct tcp_pcb *pcb) -{ - err_t err; - struct pbuf *p; - u8_t optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb); - - LWIP_ASSERT("tcp_keepalive: invalid pcb", pcb != NULL); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to ")); - ip_addr_debug_print_val(TCP_DEBUG, pcb->remote_ip); - LWIP_DEBUGF(TCP_DEBUG, ("\n")); - - 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, (u16_t)pcb->keep_cnt_sent)); - - p = tcp_output_alloc_header(pcb, optlen, 0, lwip_htonl(pcb->snd_nxt - 1)); - if (p == NULL) { - LWIP_DEBUGF(TCP_DEBUG, - ("tcp_keepalive: could not allocate memory for pbuf\n")); - return ERR_MEM; - } - tcp_output_fill_options(pcb, p, 0, optlen); - err = tcp_output_control_segment(pcb, p, &pcb->local_ip, &pcb->remote_ip); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F" err %d.\n", - pcb->snd_nxt - 1, pcb->rcv_nxt, (int)err)); - return err; -} - -/** - * 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 - */ -err_t -tcp_zero_window_probe(struct tcp_pcb *pcb) -{ - err_t err; - struct pbuf *p; - struct tcp_hdr *tcphdr; - struct tcp_seg *seg; - u16_t len; - u8_t is_fin; - u32_t snd_nxt; - u8_t optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb); - - LWIP_ASSERT("tcp_zero_window_probe: invalid pcb", pcb != NULL); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to ")); - ip_addr_debug_print_val(TCP_DEBUG, pcb->remote_ip); - LWIP_DEBUGF(TCP_DEBUG, ("\n")); - - 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, (u16_t)pcb->keep_cnt_sent)); - - /* Only consider unsent, persist timer should be off when there is data in-flight */ - seg = pcb->unsent; - if (seg == NULL) { - /* Not expected, persist timer should be off when the send buffer is empty */ - return ERR_OK; - } - - /* increment probe count. NOTE: we record probe even if it fails - to actually transmit due to an error. This ensures memory exhaustion/ - routing problem doesn't leave a zero-window pcb as an indefinite zombie. - RTO mechanism has similar behavior, see pcb->nrtx */ - if (pcb->persist_probe < 0xFF) { - ++pcb->persist_probe; - } - - 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, optlen, len, seg->tcphdr->seqno); - if (p == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n")); - return ERR_MEM; - } - tcphdr = (struct tcp_hdr *)p->payload; - - if (is_fin) { - /* FIN segment, no data */ - TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN); - } else { - /* Data segment, copy in one byte from the head of the unacked queue */ - char *d = ((char *)p->payload + TCP_HLEN); - /* Depending on whether the segment has already been sent (unacked) or not - (unsent), seg->p->payload points to the IP header or TCP header. - Ensure we copy the first TCP data byte: */ - pbuf_copy_partial(seg->p, d, 1, seg->p->tot_len - seg->len); - } - - /* The byte may be acknowledged without the window being opened. */ - snd_nxt = lwip_ntohl(seg->tcphdr->seqno) + 1; - if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { - pcb->snd_nxt = snd_nxt; - } - tcp_output_fill_options(pcb, p, 0, optlen); - - err = tcp_output_control_segment(pcb, p, &pcb->local_ip, &pcb->remote_ip); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F - " ackno %"U32_F" err %d.\n", - pcb->snd_nxt - 1, pcb->rcv_nxt, (int)err)); - return err; -} -#endif /* LWIP_TCP */ diff --git a/core/c/core/timeouts.c b/core/c/core/timeouts.c deleted file mode 100755 index c3431e8..0000000 --- a/core/c/core/timeouts.c +++ /dev/null @@ -1,451 +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/timeouts.h" -#include "lwip/priv/tcp_priv.h" - -#include "lwip/def.h" -#include "lwip/memp.h" -#include "lwip/priv/tcpip_priv.h" - -#include "lwip/ip4_frag.h" -#include "lwip/etharp.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" -#include "lwip/igmp.h" -#include "lwip/dns.h" -#include "lwip/nd6.h" -#include "lwip/ip6_frag.h" -#include "lwip/mld6.h" -#include "lwip/dhcp6.h" -#include "lwip/sys.h" -#include "lwip/pbuf.h" - -#if LWIP_DEBUG_TIMERNAMES -#define HANDLER(x) x, #x -#else /* LWIP_DEBUG_TIMERNAMES */ -#define HANDLER(x) x -#endif /* LWIP_DEBUG_TIMERNAMES */ - -#define LWIP_MAX_TIMEOUT 0x7fffffff - -/* Check if timer's expiry time is greater than time and care about u32_t wraparounds */ -#define TIME_LESS_THAN(t, compare_to) ( (((u32_t)((t)-(compare_to))) > LWIP_MAX_TIMEOUT) ? 1 : 0 ) - -/** This array contains all stack-internal cyclic timers. To get the number of - * timers, use LWIP_ARRAYSIZE() */ -const struct lwip_cyclic_timer lwip_cyclic_timers[] = { -#if LWIP_TCP - /* The TCP timer is a special case: it does not have to run always and - is triggered to start from TCP using tcp_timer_needed() */ - {TCP_TMR_INTERVAL, HANDLER(tcp_tmr)}, -#endif /* LWIP_TCP */ -#if LWIP_IPV4 -#if IP_REASSEMBLY - {IP_TMR_INTERVAL, HANDLER(ip_reass_tmr)}, -#endif /* IP_REASSEMBLY */ -#if LWIP_ARP - {ARP_TMR_INTERVAL, HANDLER(etharp_tmr)}, -#endif /* LWIP_ARP */ -#if LWIP_DHCP - {DHCP_COARSE_TIMER_MSECS, HANDLER(dhcp_coarse_tmr)}, - {DHCP_FINE_TIMER_MSECS, HANDLER(dhcp_fine_tmr)}, -#endif /* LWIP_DHCP */ -#if LWIP_AUTOIP - {AUTOIP_TMR_INTERVAL, HANDLER(autoip_tmr)}, -#endif /* LWIP_AUTOIP */ -#if LWIP_IGMP - {IGMP_TMR_INTERVAL, HANDLER(igmp_tmr)}, -#endif /* LWIP_IGMP */ -#endif /* LWIP_IPV4 */ -#if LWIP_DNS - {DNS_TMR_INTERVAL, HANDLER(dns_tmr)}, -#endif /* LWIP_DNS */ -#if LWIP_IPV6 - {ND6_TMR_INTERVAL, HANDLER(nd6_tmr)}, -#if LWIP_IPV6_REASS - {IP6_REASS_TMR_INTERVAL, HANDLER(ip6_reass_tmr)}, -#endif /* LWIP_IPV6_REASS */ -#if LWIP_IPV6_MLD - {MLD6_TMR_INTERVAL, HANDLER(mld6_tmr)}, -#endif /* LWIP_IPV6_MLD */ -#if LWIP_IPV6_DHCP6 - {DHCP6_TIMER_MSECS, HANDLER(dhcp6_tmr)}, -#endif /* LWIP_IPV6_DHCP6 */ -#endif /* LWIP_IPV6 */ -}; -const int lwip_num_cyclic_timers = LWIP_ARRAYSIZE(lwip_cyclic_timers); - -#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM - -/** The one and only timeout list */ -static struct sys_timeo *next_timeout; - -static u32_t current_timeout_due_time; - -#if LWIP_TESTMODE -struct sys_timeo** -sys_timeouts_get_next_timeout(void) -{ - return &next_timeout; -} -#endif - -#if LWIP_TCP -/** global variable that shows if the tcp timer is currently scheduled or not */ -static int tcpip_tcp_timer_active; - -/** - * Timer callback function that calls tcp_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -tcpip_tcp_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - - /* call TCP timer handler */ - tcp_tmr(); - /* timer still needed? */ - if (tcp_active_pcbs || tcp_tw_pcbs) { - /* restart timer */ - sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); - } else { - /* disable timer */ - tcpip_tcp_timer_active = 0; - } -} - -/** - * Called from TCP_REG when registering a new PCB: - * the reason is to have the TCP timer only running when - * there are active (or time-wait) PCBs. - */ -void -tcp_timer_needed(void) -{ - LWIP_ASSERT_CORE_LOCKED(); - - /* timer is off but needed again? */ - if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { - /* enable and start timer */ - tcpip_tcp_timer_active = 1; - sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); - } -} -#endif /* LWIP_TCP */ - -static void -#if LWIP_DEBUG_TIMERNAMES -sys_timeout_abs(u32_t abs_time, sys_timeout_handler handler, void *arg, const char *handler_name) -#else /* LWIP_DEBUG_TIMERNAMES */ -sys_timeout_abs(u32_t abs_time, sys_timeout_handler handler, void *arg) -#endif -{ - 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 = abs_time; - -#if LWIP_DEBUG_TIMERNAMES - timeout->handler_name = handler_name; - LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p abs_time=%"U32_F" handler=%s arg=%p\n", - (void *)timeout, abs_time, handler_name, (void *)arg)); -#endif /* LWIP_DEBUG_TIMERNAMES */ - - if (next_timeout == NULL) { - next_timeout = timeout; - return; - } - if (TIME_LESS_THAN(timeout->time, next_timeout->time)) { - timeout->next = next_timeout; - next_timeout = timeout; - } else { - for (t = next_timeout; t != NULL; t = t->next) { - if ((t->next == NULL) || TIME_LESS_THAN(timeout->time, t->next->time)) { - timeout->next = t->next; - t->next = timeout; - break; - } - } - } -} - -/** - * Timer callback function that calls cyclic->handler() and reschedules itself. - * - * @param arg unused argument - */ -#if !LWIP_TESTMODE -static -#endif -void -lwip_cyclic_timer(void *arg) -{ - u32_t now; - u32_t next_timeout_time; - const struct lwip_cyclic_timer *cyclic = (const struct lwip_cyclic_timer *)arg; - -#if LWIP_DEBUG_TIMERNAMES - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: %s()\n", cyclic->handler_name)); -#endif - cyclic->handler(); - - now = sys_now(); - next_timeout_time = (u32_t)(current_timeout_due_time + cyclic->interval_ms); /* overflow handled by TIME_LESS_THAN macro */ - if (TIME_LESS_THAN(next_timeout_time, now)) { - /* timer would immediately expire again -> "overload" -> restart without any correction */ -#if LWIP_DEBUG_TIMERNAMES - sys_timeout_abs((u32_t)(now + cyclic->interval_ms), lwip_cyclic_timer, arg, cyclic->handler_name); -#else - sys_timeout_abs((u32_t)(now + cyclic->interval_ms), lwip_cyclic_timer, arg); -#endif - - } else { - /* correct cyclic interval with handler execution delay and sys_check_timeouts jitter */ -#if LWIP_DEBUG_TIMERNAMES - sys_timeout_abs(next_timeout_time, lwip_cyclic_timer, arg, cyclic->handler_name); -#else - sys_timeout_abs(next_timeout_time, lwip_cyclic_timer, arg); -#endif - } -} - -/** Initialize this module */ -void sys_timeouts_init(void) -{ - size_t i; - /* tcp_tmr() at index 0 is started on demand */ - for (i = (LWIP_TCP ? 1 : 0); i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) { - /* we have to cast via size_t to get rid of const warning - (this is OK as cyclic_timer() casts back to const* */ - sys_timeout(lwip_cyclic_timers[i].interval_ms, lwip_cyclic_timer, LWIP_CONST_CAST(void *, &lwip_cyclic_timers[i])); - } -} - -/** - * 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 */ -{ - u32_t next_timeout_time; - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ASSERT("Timeout time too long, max is LWIP_UINT32_MAX/4 msecs", msecs <= (LWIP_UINT32_MAX / 4)); - - next_timeout_time = (u32_t)(sys_now() + msecs); /* overflow handled by TIME_LESS_THAN macro */ - -#if LWIP_DEBUG_TIMERNAMES - sys_timeout_abs(next_timeout_time, handler, arg, handler_name); -#else - sys_timeout_abs(next_timeout_time, handler, arg); -#endif -} - -/** - * Go through timeout list (for this task only) and remove the first matching - * entry (subsequent entries remain untouched), even though the timeout has not - * triggered yet. - * - * @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; - - LWIP_ASSERT_CORE_LOCKED(); - - 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; - } - memp_free(MEMP_SYS_TIMEOUT, t); - return; - } - } - return; -} - -/** - * @ingroup lwip_nosys - * 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) -{ - u32_t now; - - LWIP_ASSERT_CORE_LOCKED(); - - /* Process only timers expired at the start of the function. */ - now = sys_now(); - - do { - struct sys_timeo *tmptimeout; - sys_timeout_handler handler; - void *arg; - - PBUF_CHECK_FREE_OOSEQ(); - - tmptimeout = next_timeout; - if (tmptimeout == NULL) { - return; - } - - if (TIME_LESS_THAN(now, tmptimeout->time)) { - return; - } - - /* Timeout has expired */ - next_timeout = tmptimeout->next; - handler = tmptimeout->h; - arg = tmptimeout->arg; - current_timeout_due_time = tmptimeout->time; -#if LWIP_DEBUG_TIMERNAMES - if (handler != NULL) { - LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s t=%"U32_F" arg=%p\n", - tmptimeout->handler_name, sys_now() - tmptimeout->time, arg)); - } -#endif /* LWIP_DEBUG_TIMERNAMES */ - memp_free(MEMP_SYS_TIMEOUT, tmptimeout); - if (handler != NULL) { - handler(arg); - } - LWIP_TCPIP_THREAD_ALIVE(); - - /* Repeat until all expired timers have been called */ - } while (1); -} - -/** Rebase the timeout times to the current time. - * 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) -{ - u32_t now; - u32_t base; - struct sys_timeo *t; - - if (next_timeout == NULL) { - return; - } - - now = sys_now(); - base = next_timeout->time; - - for (t = next_timeout; t != NULL; t = t->next) { - t->time = (t->time - base) + now; - } -} - -/** Return the time left before the next timeout is due. If no timeouts are - * enqueued, returns 0xffffffff - */ -u32_t -sys_timeouts_sleeptime(void) -{ - u32_t now; - - LWIP_ASSERT_CORE_LOCKED(); - - if (next_timeout == NULL) { - return SYS_TIMEOUTS_SLEEPTIME_INFINITE; - } - now = sys_now(); - if (TIME_LESS_THAN(next_timeout->time, now)) { - return 0; - } else { - u32_t ret = (u32_t)(next_timeout->time - now); - LWIP_ASSERT("invalid sleeptime", ret <= LWIP_MAX_TIMEOUT); - return ret; - } -} - -#else /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ -/* Satisfy the TCP code which calls this function */ -void -tcp_timer_needed(void) -{ -} -#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ diff --git a/core/c/core/udp.c b/core/c/core/udp.c deleted file mode 100755 index 95bbec3..0000000 --- a/core/c/core/udp.c +++ /dev/null @@ -1,1424 +0,0 @@ -/** - * @file - * User Datagram Protocol module\n - * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).\n - * See also @ref udp_raw - * - * @defgroup udp_raw UDP - * @ingroup callbackstyle_api - * User Datagram Protocol module\n - * @see @ref api - */ - -/* - * 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 - * - */ - -/* @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/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/netif.h" -#include "lwip/icmp.h" -#include "lwip/icmp6.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "lwip/dhcp.h" - -#include - -#ifndef UDP_LOCAL_PORT_RANGE_START -/* From http://www.iana.org/assignments/port-numbers: - "The Dynamic and/or Private Ports are those from 49152 through 65535" */ -#define UDP_LOCAL_PORT_RANGE_START 0xc000 -#define UDP_LOCAL_PORT_RANGE_END 0xffff -#define UDP_ENSURE_LOCAL_PORT_RANGE(port) ((u16_t)(((port) & (u16_t)~UDP_LOCAL_PORT_RANGE_START) + UDP_LOCAL_PORT_RANGE_START)) -#endif - -/* last local UDP port */ -static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START; - -/* The list of UDP PCBs */ -/* exported in udp.h (was static) */ -struct udp_pcb *udp_pcbs; - -/** - * Initialize this module. - */ -void -udp_init(void) -{ -#ifdef LWIP_RAND - udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); -#endif /* LWIP_RAND */ -} - -/** - * Allocate a new local UDP port. - * - * @return a new (free) local UDP port number - */ -static u16_t -udp_new_port(void) -{ - u16_t n = 0; - struct udp_pcb *pcb; - -again: - if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) { - udp_port = UDP_LOCAL_PORT_RANGE_START; - } - /* Check all PCBs. */ - for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { - if (pcb->local_port == udp_port) { - if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) { - return 0; - } - goto again; - } - } - return udp_port; -} - -/** Common code to see if the current input packet matches the pcb - * (current input packet is accessed via ip(4/6)_current_* macros) - * - * @param pcb pcb to check - * @param inp network interface on which the datagram was received (only used for IPv4) - * @param broadcast 1 if his is an IPv4 broadcast (global or subnet-only), 0 otherwise (only used for IPv4) - * @return 1 on match, 0 otherwise - */ -static u8_t -udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast) -{ - LWIP_UNUSED_ARG(inp); /* in IPv6 only case */ - LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ - - LWIP_ASSERT("udp_input_local_match: invalid pcb", pcb != NULL); - LWIP_ASSERT("udp_input_local_match: invalid netif", inp != NULL); - - /* check if PCB is bound to specific netif */ - if ((pcb->netif_idx != NETIF_NO_INDEX) && - (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { - return 0; - } - - /* Dual-stack: PCBs listening to any IP type also listen to any IP address */ - if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { -#if LWIP_IPV4 && IP_SOF_BROADCAST_RECV - if ((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) { - return 0; - } -#endif /* LWIP_IPV4 && IP_SOF_BROADCAST_RECV */ - return 1; - } - - /* Only need to check PCB if incoming IP version matches PCB IP version */ - if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) { -#if LWIP_IPV4 - /* Special case: IPv4 broadcast: all or broadcasts in my subnet - * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */ - if (broadcast != 0) { -#if IP_SOF_BROADCAST_RECV - if (ip_get_option(pcb, SOF_BROADCAST)) -#endif /* IP_SOF_BROADCAST_RECV */ - { - if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip)) || - ((ip4_current_dest_addr()->addr == IPADDR_BROADCAST)) || - ip4_addr_netcmp(ip_2_ip4(&pcb->local_ip), ip4_current_dest_addr(), netif_ip4_netmask(inp))) { - return 1; - } - } - } else -#endif /* LWIP_IPV4 */ - /* Handle IPv4 and IPv6: all or exact match */ - if (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { - return 1; - } - } - - return 0; -} - -/** - * 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 (p->payload pointing to the UDP header) - * @param inp network interface on which the datagram was received. - * - */ -void -udp_input(struct pbuf *p, struct netif *inp) -{ - struct udp_hdr *udphdr; - struct udp_pcb *pcb, *prev; - struct udp_pcb *uncon_pcb; - u16_t src, dest; - u8_t broadcast; - u8_t for_us = 0; - - LWIP_UNUSED_ARG(inp); - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ASSERT("udp_input: invalid pbuf", p != NULL); - LWIP_ASSERT("udp_input: invalid netif", inp != NULL); - - PERF_START; - - UDP_STATS_INC(udp.recv); - - /* Check minimum length (UDP header) */ - if (p->len < UDP_HLEN) { - /* drop short packets */ - LWIP_DEBUGF(UDP_DEBUG, - ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); - UDP_STATS_INC(udp.lenerr); - UDP_STATS_INC(udp.drop); - MIB2_STATS_INC(mib2.udpinerrors); - pbuf_free(p); - goto end; - } - - udphdr = (struct udp_hdr *)p->payload; - - /* is broadcast packet ? */ - broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); - - 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 = lwip_ntohs(udphdr->src); - dest = lwip_ntohs(udphdr->dest); - - udp_debug_print(udphdr); - - /* print the UDP source and destination */ - LWIP_DEBUGF(UDP_DEBUG, ("udp (")); - ip_addr_debug_print_val(UDP_DEBUG, *ip_current_dest_addr()); - LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", lwip_ntohs(udphdr->dest))); - ip_addr_debug_print_val(UDP_DEBUG, *ip_current_src_addr()); - LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", lwip_ntohs(udphdr->src))); - - pcb = NULL; - prev = NULL; - 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) { - -#if TUN2SOCKS - // go-tun2socks logic - // take the first one, library users are responsible for creating that pcb - break; -#endif /* TUN2SOCKS */ - - /* print the PCB local and remote address */ - LWIP_DEBUGF(UDP_DEBUG, ("pcb (")); - ip_addr_debug_print_val(UDP_DEBUG, pcb->local_ip); - LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port)); - ip_addr_debug_print_val(UDP_DEBUG, pcb->remote_ip); - LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); - - /* compare PCB local addr+port to UDP destination addr+port */ - if ((pcb->local_port == dest) && - (udp_input_local_match(pcb, inp, broadcast) != 0)) { - if ((pcb->flags & UDP_FLAGS_CONNECTED) == 0) { - if (uncon_pcb == NULL) { - /* the first unconnected matching PCB */ - uncon_pcb = pcb; -#if LWIP_IPV4 - } else if (broadcast && ip4_current_dest_addr()->addr == IPADDR_BROADCAST) { - /* global broadcast address (only valid for IPv4; match was checked before) */ - if (!IP_IS_V4_VAL(uncon_pcb->local_ip) || !ip4_addr_cmp(ip_2_ip4(&uncon_pcb->local_ip), netif_ip4_addr(inp))) { - /* uncon_pcb does not match the input netif, check this pcb */ - if (IP_IS_V4_VAL(pcb->local_ip) && ip4_addr_cmp(ip_2_ip4(&pcb->local_ip), netif_ip4_addr(inp))) { - /* better match */ - uncon_pcb = pcb; - } - } -#endif /* LWIP_IPV4 */ - } -#if SO_REUSE - else if (!ip_addr_isany(&pcb->local_ip)) { - /* prefer specific IPs over catch-all */ - uncon_pcb = pcb; - } -#endif /* SO_REUSE */ - } - - /* compare PCB remote addr+port to UDP source addr+port */ - if ((pcb->remote_port == src) && - (ip_addr_isany_val(pcb->remote_ip) || - ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { - /* 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) { - for_us = 1; - } else { -#if LWIP_IPV6 - if (ip_current_is_v6()) { - for_us = netif_get_ip6_addr_match(inp, ip6_current_dest_addr()) >= 0; - } -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 - if (!ip_current_is_v6()) { - for_us = ip4_addr_cmp(netif_ip4_addr(inp), ip4_current_dest_addr()); - } -#endif /* LWIP_IPV4 */ - } - - if (for_us) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); -#if CHECKSUM_CHECK_UDP - IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_UDP) { -#if LWIP_UDPLITE - if (ip_current_header_proto() == IP_PROTO_UDPLITE) { - /* Do the UDP Lite checksum */ - u16_t chklen = lwip_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) */ - goto chkerr; - } - } - if (ip_chksum_pseudo_partial(p, IP_PROTO_UDPLITE, - p->tot_len, chklen, - ip_current_src_addr(), ip_current_dest_addr()) != 0) { - goto chkerr; - } - } else -#endif /* LWIP_UDPLITE */ - { - if (udphdr->chksum != 0) { - if (ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, - ip_current_src_addr(), - ip_current_dest_addr()) != 0) { - goto chkerr; - } - } - } - } -#endif /* CHECKSUM_CHECK_UDP */ - if (pbuf_remove_header(p, UDP_HLEN)) { - /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_remove_header failed\n", 0); - UDP_STATS_INC(udp.drop); - MIB2_STATS_INC(mib2.udpinerrors); - pbuf_free(p); - goto end; - } - - if (pcb != NULL) { - MIB2_STATS_INC(mib2.udpindatagrams); -#if SO_REUSE && SO_REUSE_RXTOALL - if (ip_get_option(pcb, SOF_REUSEADDR) && - (broadcast || ip_addr_ismulticast(ip_current_dest_addr()))) { - /* pass broadcast- or multicast packets to all multicast pcbs - if SOF_REUSEADDR is set on the first match */ - struct udp_pcb *mpcb; - 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) && - (udp_input_local_match(mpcb, inp, broadcast) != 0)) { - /* pass a copy of the packet to all local matches */ - if (mpcb->recv != NULL) { - struct pbuf *q; - q = pbuf_clone(PBUF_RAW, PBUF_POOL, p); - if (q != NULL) { - mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); - } - } - } - } - } - } -#endif /* SO_REUSE && SO_REUSE_RXTOALL */ - /* callback */ - if (pcb->recv != NULL) { -#if TUN2SOCKS - // go-tun2socks logic - // Since we are accepting all udp datagrams using the default netif and - // and the default pcb, and the address of the default pcb need not to match - // the packet's dest address in tun2socks, our application will never - // know what are the original dest address and port if we don't pass them - // to the recv callback. - pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src, ip_current_dest_addr(), dest); -#else - /* now the recv function is responsible for freeing p */ - pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); -#endif /* TUN2SOCKS */ - } 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 || LWIP_ICMP6 - /* No match was found, send ICMP destination port unreachable unless - destination address was broadcast/multicast. */ - if (!broadcast && !ip_addr_ismulticast(ip_current_dest_addr())) { - /* move payload pointer back to ip header */ - pbuf_header_force(p, (s16_t)(ip_current_header_tot_len() + UDP_HLEN)); - icmp_port_unreach(ip_current_is_v6(), p); - } -#endif /* LWIP_ICMP || LWIP_ICMP6 */ - UDP_STATS_INC(udp.proterr); - UDP_STATS_INC(udp.drop); - MIB2_STATS_INC(mib2.udpnoports); - pbuf_free(p); - } - } else { - pbuf_free(p); - } -end: - PERF_STOP("udp_input"); - return; -#if CHECKSUM_CHECK_UDP -chkerr: - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("udp_input: UDP (or UDP Lite) datagram discarded due to failing checksum\n")); - UDP_STATS_INC(udp.chkerr); - UDP_STATS_INC(udp.drop); - MIB2_STATS_INC(mib2.udpinerrors); - pbuf_free(p); - PERF_STOP("udp_input"); -#endif /* CHECKSUM_CHECK_UDP */ -} - -/** - * @ingroup udp_raw - * Sends the pbuf p using UDP. The pbuf is not deallocated. - * - * - * @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 occurred. - * - ERR_MEM. Out of memory. - * - ERR_RTE. Could not find route to destination address. - * - ERR_VAL. No PCB or PCB is dual-stack - * - More errors could be returned by lower protocol layers. - * - * @see udp_disconnect() udp_sendto() - */ -err_t -udp_send(struct udp_pcb *pcb, struct pbuf *p) -{ - LWIP_ERROR("udp_send: invalid pcb", pcb != NULL, return ERR_ARG); - LWIP_ERROR("udp_send: invalid pbuf", p != NULL, return ERR_ARG); - - if (IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) { - return ERR_VAL; - } - -#if TUN2SOCKS - /* tun2socks should never use udp_send(), use udp_sendto() directly instead */ - return ERR_OK; -#else - /* send to the packet using remote ip and port stored in the pcb */ - return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); -#endif /* TUN2SOCKS */ -} - -#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP -/** @ingroup udp_raw - * Same as udp_send() but with checksum - */ -err_t -udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, - u8_t have_chksum, u16_t chksum) -{ - LWIP_ERROR("udp_send_chksum: invalid pcb", pcb != NULL, return ERR_ARG); - LWIP_ERROR("udp_send_chksum: invalid pbuf", p != NULL, return ERR_ARG); - - if (IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) { - return ERR_VAL; - } - -#if TUN2SOCKS - /* tun2socks should never use udp_send(), use udp_sendto_chksum() directly instead */ - return ERR_OK; -#else - /* 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 /* TUN2SOCKS */ -} -#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - -/** - * @ingroup udp_raw - * 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() - */ -#if TUN2SOCKS -err_t -udp_sendto(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, const ip_addr_t *src_ip, u16_t src_port) -{ -#else -err_t -udp_sendto(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port) -{ -#endif /* TUN2SOCKS */ -#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP -#if TUN2SOCKS - return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0, src_ip, src_port); -} - -/** @ingroup udp_raw - * Same as udp_sendto(), but with checksum */ -err_t -udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, - u16_t dst_port, u8_t have_chksum, u16_t chksum, const ip_addr_t *src_ip, u16_t src_port) -{ -#else - return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0); -} - -/** @ingroup udp_raw - * Same as udp_sendto(), but with checksum */ -err_t -udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, - u16_t dst_port, u8_t have_chksum, u16_t chksum) -{ -#endif /* TUN2SOCKS */ -#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - struct netif *netif; - - LWIP_ERROR("udp_sendto: invalid pcb", pcb != NULL, return ERR_ARG); - LWIP_ERROR("udp_sendto: invalid pbuf", p != NULL, return ERR_ARG); - LWIP_ERROR("udp_sendto: invalid dst_ip", dst_ip != NULL, return ERR_ARG); - - if (!IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { - return ERR_VAL; - } - - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); - - if (pcb->netif_idx != NETIF_NO_INDEX) { - netif = netif_get_by_index(pcb->netif_idx); - } else { -#if LWIP_MULTICAST_TX_OPTIONS - netif = NULL; - if (ip_addr_ismulticast(dst_ip)) { - /* For IPv6, the interface to use for packets with a multicast destination - * is specified using an interface index. The same approach may be used for - * IPv4 as well, in which case it overrides the IPv4 multicast override - * address below. Here we have to look up the netif by going through the - * list, but by doing so we skip a route lookup. If the interface index has - * gone stale, we fall through and do the regular route lookup after all. */ - if (pcb->mcast_ifindex != NETIF_NO_INDEX) { - netif = netif_get_by_index(pcb->mcast_ifindex); - } -#if LWIP_IPV4 - else -#if LWIP_IPV6 - if (IP_IS_V4(dst_ip)) -#endif /* LWIP_IPV6 */ - { - /* IPv4 does not use source-based routing by default, so we use an - administratively selected interface for multicast by default. - However, this can be overridden by setting an interface address - in pcb->mcast_ip4 that is used for routing. If this routing lookup - fails, we try regular routing as though no override was set. */ - if (!ip4_addr_isany_val(pcb->mcast_ip4) && - !ip4_addr_cmp(&pcb->mcast_ip4, IP4_ADDR_BROADCAST)) { - netif = ip4_route_src(ip_2_ip4(&pcb->local_ip), &pcb->mcast_ip4); - } - } -#endif /* LWIP_IPV4 */ - } - - if (netif == NULL) -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - { - /* find the outgoing network interface for this packet */ - netif = ip_route(&pcb->local_ip, dst_ip); - } - } - - /* no outgoing network interface could be found? */ - if (netif == NULL) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to ")); - ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, dst_ip); - LWIP_DEBUGF(UDP_DEBUG, ("\n")); - UDP_STATS_INC(udp.rterr); - return ERR_RTE; - } -#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP -#if TUN2SOCKS - return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum, src_ip, src_port); -#else - return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); -#endif /* TUN2SOCKS */ -#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ -#if TUN2SOCKS - return udp_sendto_if(pcb, p, dst_ip, dst_port, netif, src_ip, src_port); -#else - return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); -#endif /* TUN2SOCKS */ -#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ -} - -/** - * @ingroup udp_raw - * 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() - */ -#if TUN2SOCKS -err_t -udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, const ip_addr_t *src_ip, u16_t src_port) -{ -#else -err_t -udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) -{ -#endif /* TUN2SOCKS */ -#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP -#if TUN2SOCKS - return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0, src_ip, src_port); -} - -/** Same as udp_sendto_if(), but with checksum */ -err_t -udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, - u16_t dst_port, struct netif *netif, u8_t have_chksum, - u16_t chksum, const ip_addr_t *src_ip, u16_t src_port) -{ -#else - return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0); -} - -/** Same as udp_sendto_if(), but with checksum */ -err_t -udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, - u16_t dst_port, struct netif *netif, u8_t have_chksum, - u16_t chksum) -{ -#endif /* TUN2SOCKS */ -#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ -#if TUN2SOCKS -#else - const ip_addr_t *src_ip; -#endif /* TUN2SOCKS */ - - LWIP_ERROR("udp_sendto_if: invalid pcb", pcb != NULL, return ERR_ARG); - LWIP_ERROR("udp_sendto_if: invalid pbuf", p != NULL, return ERR_ARG); - LWIP_ERROR("udp_sendto_if: invalid dst_ip", dst_ip != NULL, return ERR_ARG); - LWIP_ERROR("udp_sendto_if: invalid netif", netif != NULL, return ERR_ARG); - - if (!IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { - return ERR_VAL; - } - -#if TUN2SOCKS -#else - /* PCB local address is IP_ANY_ADDR or multicast? */ -#if LWIP_IPV6 - if (IP_IS_V6(dst_ip)) { - if (ip6_addr_isany(ip_2_ip6(&pcb->local_ip)) || - ip6_addr_ismulticast(ip_2_ip6(&pcb->local_ip))) { - src_ip = ip6_select_source_address(netif, ip_2_ip6(dst_ip)); - if (src_ip == NULL) { - /* No suitable source address was found. */ - return ERR_RTE; - } - } else { - /* use UDP PCB local IPv6 address as source address, if still valid. */ - if (netif_get_ip6_addr_match(netif, ip_2_ip6(&pcb->local_ip)) < 0) { - /* Address isn't valid anymore. */ - return ERR_RTE; - } - src_ip = &pcb->local_ip; - } - } -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 && LWIP_IPV6 - else -#endif /* LWIP_IPV4 && LWIP_IPV6 */ -#if LWIP_IPV4 - if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip)) || - ip4_addr_ismulticast(ip_2_ip4(&pcb->local_ip))) { - /* if the local_ip is any or multicast - * use the outgoing network interface IP address as source address */ - src_ip = netif_ip_addr4(netif); - } else { - /* check if UDP PCB local IP address is correct - * this could be an old address if netif->ip_addr has changed */ - if (!ip4_addr_cmp(ip_2_ip4(&(pcb->local_ip)), netif_ip4_addr(netif))) { - /* local_ip doesn't match, drop the packet */ - return ERR_RTE; - } - /* use UDP PCB local IP address as source address */ - src_ip = &pcb->local_ip; - } -#endif /* LWIP_IPV4 */ -#endif /* TUN2SOCKS */ -#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP -#if TUN2SOCKS - return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum, src_ip, src_port); -#else - return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum, src_ip); -#endif /* TUN2SOCKS */ -#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ -#if TUN2SOCKS - return udp_sendto_if_src(pcb, p, dst_ip, dst_port, netif, src_ip, src_port); -#else - return udp_sendto_if_src(pcb, p, dst_ip, dst_port, netif, src_ip); -#endif /* TUN2SOCKS */ -#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ -} - -/** @ingroup udp_raw - * Same as @ref udp_sendto_if, but with source address */ -#if TUN2SOCKS -err_t -udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, const ip_addr_t *src_ip, u16_t src_port) -{ -#else -err_t -udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, const ip_addr_t *src_ip) -{ -#endif /* TUN2SOCKS */ -#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP -#if TUN2SOCKS - return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0, src_ip, src_port); -} - -/** Same as udp_sendto_if_src(), but with checksum */ -err_t -udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, - u16_t dst_port, struct netif *netif, u8_t have_chksum, - u16_t chksum, const ip_addr_t *src_ip, u16_t src_port) -{ -#else - return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0, src_ip); -} - -/** Same as udp_sendto_if_src(), but with checksum */ -err_t -udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, - u16_t dst_port, struct netif *netif, u8_t have_chksum, - u16_t chksum, const ip_addr_t *src_ip) -{ -#endif /* TUN2SOCKS */ -#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - struct udp_hdr *udphdr; - err_t err; - struct pbuf *q; /* q will be sent down the stack */ - u8_t ip_proto; - u8_t ttl; - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("udp_sendto_if_src: invalid pcb", pcb != NULL, return ERR_ARG); - LWIP_ERROR("udp_sendto_if_src: invalid pbuf", p != NULL, return ERR_ARG); - LWIP_ERROR("udp_sendto_if_src: invalid dst_ip", dst_ip != NULL, return ERR_ARG); - LWIP_ERROR("udp_sendto_if_src: invalid src_ip", src_ip != NULL, return ERR_ARG); - LWIP_ERROR("udp_sendto_if_src: invalid netif", netif != NULL, return ERR_ARG); - - if (!IP_ADDR_PCB_VERSION_MATCH(pcb, src_ip) || - !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { - return ERR_VAL; - } - -#if LWIP_IPV4 && IP_SOF_BROADCAST - /* broadcast filter? */ - if (!ip_get_option(pcb, SOF_BROADCAST) && -#if LWIP_IPV6 - IP_IS_V4(dst_ip) && -#endif /* LWIP_IPV6 */ - ip_addr_isbroadcast(dst_ip, netif)) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); - return ERR_VAL; - } -#endif /* LWIP_IPV4 && 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; - } - } - - /* packet too large to add a UDP header without causing an overflow? */ - if ((u16_t)(p->tot_len + UDP_HLEN) < p->tot_len) { - return ERR_MEM; - } - /* not enough space to add an UDP header to first pbuf in given p chain? */ - if (pbuf_add_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; -#if TUN2SOCKS - udphdr->src = lwip_htons(src_port); -#else - udphdr->src = lwip_htons(pcb->local_port); -#endif /* TUN2SOCKS */ - udphdr->dest = lwip_htons(dst_port); - /* in UDP, 0 checksum means 'no checksum' */ - udphdr->chksum = 0x0000; - - /* Multicast Loop? */ -#if LWIP_MULTICAST_TX_OPTIONS - if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) && ip_addr_ismulticast(dst_ip)) { - q->flags |= PBUF_FLAG_MCASTLOOP; - } -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - - 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 = lwip_htons(chklen_hdr); - /* calculate checksum */ -#if CHECKSUM_GEN_UDP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_UDP) { -#if LWIP_CHECKSUM_ON_COPY - if (have_chksum) { - chklen = UDP_HLEN; - } -#endif /* LWIP_CHECKSUM_ON_COPY */ - udphdr->chksum = ip_chksum_pseudo_partial(q, IP_PROTO_UDPLITE, - q->tot_len, chklen, src_ip, dst_ip); -#if LWIP_CHECKSUM_ON_COPY - if (have_chksum) { - u32_t acc; - acc = udphdr->chksum + (u16_t)~(chksum); - udphdr->chksum = FOLD_U32T(acc); - } -#endif /* LWIP_CHECKSUM_ON_COPY */ - - /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udphdr->chksum == 0x0000) { - udphdr->chksum = 0xffff; - } - } -#endif /* CHECKSUM_GEN_UDP */ - - ip_proto = IP_PROTO_UDPLITE; - } else -#endif /* LWIP_UDPLITE */ - { /* UDP */ - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); - udphdr->len = lwip_htons(q->tot_len); - /* calculate checksum */ -#if CHECKSUM_GEN_UDP - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_UDP) { - /* Checksum is mandatory over IPv6. */ - if (IP_IS_V6(dst_ip) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { - u16_t udpchksum; -#if LWIP_CHECKSUM_ON_COPY - if (have_chksum) { - u32_t acc; - udpchksum = ip_chksum_pseudo_partial(q, IP_PROTO_UDP, - q->tot_len, UDP_HLEN, src_ip, dst_ip); - acc = udpchksum + (u16_t)~(chksum); - udpchksum = FOLD_U32T(acc); - } else -#endif /* LWIP_CHECKSUM_ON_COPY */ - { - udpchksum = ip_chksum_pseudo(q, IP_PROTO_UDP, q->tot_len, - src_ip, dst_ip); - } - - /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udpchksum == 0x0000) { - udpchksum = 0xffff; - } - udphdr->chksum = udpchksum; - } - } -#endif /* CHECKSUM_GEN_UDP */ - ip_proto = IP_PROTO_UDP; - } - - /* Determine TTL to use */ -#if LWIP_MULTICAST_TX_OPTIONS - ttl = (ip_addr_ismulticast(dst_ip) ? udp_get_multicast_ttl(pcb) : pcb->ttl); -#else /* LWIP_MULTICAST_TX_OPTIONS */ - ttl = pcb->ttl; -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto)); - /* output to IP */ - NETIF_SET_HINTS(netif, &(pcb->netif_hints)); - err = ip_output_if_src(q, src_ip, dst_ip, ttl, pcb->tos, ip_proto, netif); - NETIF_RESET_HINTS(netif); - - /* @todo: must this be increased even if error occurred? */ - MIB2_STATS_INC(mib2.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; -} - -/** - * @ingroup udp_raw - * 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_ANY_TYPE 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 occurred. - * - ERR_USE. The specified ipaddr and port are already bound to by - * another UDP PCB. - * - * @see udp_disconnect() - */ -err_t -udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) -{ - struct udp_pcb *ipcb; - u8_t rebind; -#if LWIP_IPV6 && LWIP_IPV6_SCOPES - ip_addr_t zoned_ipaddr; -#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ - - LWIP_ASSERT_CORE_LOCKED(); - -#if LWIP_IPV4 - /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ - if (ipaddr == NULL) { - ipaddr = IP4_ADDR_ANY; - } -#else /* LWIP_IPV4 */ - LWIP_ERROR("udp_bind: invalid ipaddr", ipaddr != NULL, return ERR_ARG); -#endif /* LWIP_IPV4 */ - - LWIP_ERROR("udp_bind: invalid pcb", pcb != NULL, return ERR_ARG); - - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = ")); - ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE, 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) { - rebind = 1; - break; - } - } - -#if LWIP_IPV6 && LWIP_IPV6_SCOPES - /* If the given IP address should have a zone but doesn't, assign one now. - * This is legacy support: scope-aware callers should always provide properly - * zoned source addresses. Do the zone selection before the address-in-use - * check below; as such we have to make a temporary copy of the address. */ - if (IP_IS_V6(ipaddr) && ip6_addr_lacks_zone(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { - ip_addr_copy(zoned_ipaddr, *ipaddr); - ip6_addr_select_zone(ip_2_ip6(&zoned_ipaddr), ip_2_ip6(&zoned_ipaddr)); - ipaddr = &zoned_ipaddr; - } -#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ - - /* no port specified? */ - if (port == 0) { - port = udp_new_port(); - if (port == 0) { - /* no more ports available in local range */ - LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); - return ERR_USE; - } - } else { - for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { - if (pcb != ipcb) { - /* By default, we don't allow to bind to a port that any other udp - PCB is already bound to, unless *all* PCBs with that port have tha - REUSEADDR flag set. */ -#if SO_REUSE - if (!ip_get_option(pcb, SOF_REUSEADDR) || - !ip_get_option(ipcb, SOF_REUSEADDR)) -#endif /* SO_REUSE */ - { - /* port matches that of PCB in list and REUSEADDR not set -> reject */ - if ((ipcb->local_port == port) && - /* IP address matches or any IP used? */ - (ip_addr_cmp(&ipcb->local_ip, ipaddr) || ip_addr_isany(ipaddr) || - ip_addr_isany(&ipcb->local_ip))) { - /* 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_ipaddr(&pcb->local_ip, ipaddr); - - pcb->local_port = port; - mib2_udp_bind(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 ")); - ip_addr_debug_print_val(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, pcb->local_ip); - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port)); - return ERR_OK; -} - -/** - * @ingroup udp_raw - * Bind an UDP PCB to a specific netif. - * After calling this function, all packets received via this PCB - * are guaranteed to have come in via the specified netif, and all - * outgoing packets will go out via the specified netif. - * - * @param pcb UDP PCB to be bound. - * @param netif netif to bind udp pcb to. Can be NULL. - * - * @see udp_disconnect() - */ -void -udp_bind_netif(struct udp_pcb *pcb, const struct netif *netif) -{ - LWIP_ASSERT_CORE_LOCKED(); - - if (netif != NULL) { - pcb->netif_idx = netif_get_index(netif); - } else { - pcb->netif_idx = NETIF_NO_INDEX; - } -} - -/** - * @ingroup udp_raw - * Sets the remote end of the pcb. This function does not generate any - * network traffic, but only sets the remote address of the pcb. - * - * @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 -udp_connect(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) -{ - struct udp_pcb *ipcb; - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("udp_connect: invalid pcb", pcb != NULL, return ERR_ARG); - LWIP_ERROR("udp_connect: invalid ipaddr", ipaddr != NULL, return ERR_ARG); - - 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_ipaddr(&pcb->remote_ip, ipaddr); -#if LWIP_IPV6 && LWIP_IPV6_SCOPES - /* If the given IP address should have a zone but doesn't, assign one now, - * using the bound address to make a more informed decision when possible. */ - if (IP_IS_V6(&pcb->remote_ip) && - ip6_addr_lacks_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNKNOWN)) { - ip6_addr_select_zone(ip_2_ip6(&pcb->remote_ip), ip_2_ip6(&pcb->local_ip)); - } -#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ - - pcb->remote_port = port; - pcb->flags |= UDP_FLAGS_CONNECTED; - - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to ")); - ip_addr_debug_print_val(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - pcb->remote_ip); - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port)); - - /* Insert UDP PCB into the list of active UDP PCBs. */ - for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { - 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; -} - -/** - * @ingroup udp_raw - * Remove the remote end of the pcb. This function does not generate - * any network traffic, but only removes the remote address of the pcb. - * - * @param pcb the udp pcb to disconnect. - */ -void -udp_disconnect(struct udp_pcb *pcb) -{ - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("udp_disconnect: invalid pcb", pcb != NULL, return); - - /* reset remote address association */ -#if LWIP_IPV4 && LWIP_IPV6 - if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { - ip_addr_copy(pcb->remote_ip, *IP_ANY_TYPE); - } else { -#endif - ip_addr_set_any(IP_IS_V6_VAL(pcb->remote_ip), &pcb->remote_ip); -#if LWIP_IPV4 && LWIP_IPV6 - } -#endif - pcb->remote_port = 0; - pcb->netif_idx = NETIF_NO_INDEX; - /* mark PCB as unconnected */ - udp_clear_flags(pcb, UDP_FLAGS_CONNECTED); -} - -/** - * @ingroup udp_raw - * 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 which 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 -udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) -{ - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("udp_recv: invalid pcb", pcb != NULL, return); - - /* remember recv() callback and user data */ - pcb->recv = recv; - pcb->recv_arg = recv_arg; -} - -/** - * @ingroup udp_raw - * Removes and deallocates the 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 -udp_remove(struct udp_pcb *pcb) -{ - struct udp_pcb *pcb2; - - LWIP_ASSERT_CORE_LOCKED(); - - LWIP_ERROR("udp_remove: invalid pcb", pcb != NULL, return); - - mib2_udp_unbind(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; - break; - } - } - } - memp_free(MEMP_UDP_PCB, pcb); -} - -/** - * @ingroup udp_raw - * Creates a new UDP pcb which can be used for UDP communication. The - * pcb is not active until it has either been bound to a local address - * or connected to a remote address. - * - * @return The UDP PCB which was created. NULL if the PCB data structure - * could not be allocated. - * - * @see udp_remove() - */ -struct udp_pcb * -udp_new(void) -{ - struct udp_pcb *pcb; - - LWIP_ASSERT_CORE_LOCKED(); - - 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 */ - memset(pcb, 0, sizeof(struct udp_pcb)); - pcb->ttl = UDP_TTL; -#if LWIP_MULTICAST_TX_OPTIONS - udp_set_multicast_ttl(pcb, UDP_TTL); -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - } - return pcb; -} - -/** - * @ingroup udp_raw - * Create a UDP PCB for specific IP type. - * The pcb is not active until it has either been bound to a local address - * or connected to a remote address. - * - * @param type IP address type, see @ref lwip_ip_addr_type definitions. - * If you want to listen to IPv4 and IPv6 (dual-stack) packets, - * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. - * @return The UDP PCB which was created. NULL if the PCB data structure - * could not be allocated. - * - * @see udp_remove() - */ -struct udp_pcb * -udp_new_ip_type(u8_t type) -{ - struct udp_pcb *pcb; - - LWIP_ASSERT_CORE_LOCKED(); - - pcb = udp_new(); -#if LWIP_IPV4 && LWIP_IPV6 - if (pcb != NULL) { - IP_SET_TYPE_VAL(pcb->local_ip, type); - IP_SET_TYPE_VAL(pcb->remote_ip, type); - } -#else - LWIP_UNUSED_ARG(type); -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - return pcb; -} - -/** This function is called from netif.c when address is changed - * - * @param old_addr IP address of the netif before change - * @param new_addr IP address of the netif after change - */ -void udp_netif_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) -{ - struct udp_pcb *upcb; - - if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) { - for (upcb = udp_pcbs; upcb != NULL; upcb = upcb->next) { - /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&upcb->local_ip, old_addr)) { - /* The PCB is bound to the old ipaddr and - * is set to bound to the new one instead */ - ip_addr_copy(upcb->local_ip, *new_addr); - } - } - } -} - -#if UDP_DEBUG -/** - * Print UDP header information for debug purposes. - * - * @param udphdr pointer to the udp header in memory. - */ -void -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", - lwip_ntohs(udphdr->src), lwip_ntohs(udphdr->dest))); - LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n", - lwip_ntohs(udphdr->len), lwip_ntohs(udphdr->chksum))); - LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); -} -#endif /* UDP_DEBUG */ - -#endif /* LWIP_UDP */ diff --git a/core/c/custom/arch/bpstruct.h b/core/c/custom/arch/bpstruct.h deleted file mode 100755 index d7a4604..0000000 --- a/core/c/custom/arch/bpstruct.h +++ /dev/null @@ -1 +0,0 @@ -#pragma pack(push,1) diff --git a/core/c/custom/arch/cc.h b/core/c/custom/arch/cc.h deleted file mode 100755 index 59e3084..0000000 --- a/core/c/custom/arch/cc.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifdef _WIN32 - // both win32 and win64 are defined here - #include "cc_windows.h" -#else - #include "cc_others.h" -#endif diff --git a/core/c/custom/arch/cc_others.h b/core/c/custom/arch/cc_others.h deleted file mode 100755 index 6361f33..0000000 --- a/core/c/custom/arch/cc_others.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef LWIP_ARCH_CC_H -#define LWIP_ARCH_CC_H - -/* Include some files for defining library routines */ -#include - -#define LWIP_TIMEVAL_PRIVATE 0 - -/* Define platform endianness */ -#ifndef BYTE_ORDER -#define BYTE_ORDER LITTLE_ENDIAN -#endif /* BYTE_ORDER */ - -/* Define generic types used in lwIP */ -/* -typedef unsigned char u8_t; -typedef signed char s8_t; -typedef unsigned short u16_t; -typedef signed short s16_t; -typedef unsigned int u32_t; -typedef signed int s32_t; - -typedef unsigned long mem_ptr_t; -*/ - -/* Define (sn)printf formatters for these lwIP types */ -#define X8_F "02x" -#define U16_F "hu" -#define S16_F "hd" -#define X16_F "hx" -#define U32_F "u" -#define S32_F "d" -#define X32_F "x" - -/* If only we could use C99 and get %zu */ -#if defined(__x86_64__) -#define SZT_F "lu" -#else -#define SZT_F "u" -#endif - -/* Compiler hints for packing structures */ -#define PACK_STRUCT_FIELD(x) x -#define PACK_STRUCT_STRUCT __attribute__((packed)) -#define PACK_STRUCT_BEGIN -#define PACK_STRUCT_END - -/* prototypes for printf() and abort() */ -#include -#include -/* Plaform specific diagnostic output */ -#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) - -#ifdef LWIP_UNIX_EMPTY_ASSERT -#define LWIP_PLATFORM_ASSERT(x) -#else -#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ -x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) -#endif - -#define LWIP_RAND() ((u32_t)rand()) - -struct sio_status_s; -typedef struct sio_status_s sio_status_t; -#define sio_fd_t sio_status_t* -#define __sio_fd_t_defined - -#endif /* LWIP_ARCH_CC_H */ diff --git a/core/c/custom/arch/cc_windows.h b/core/c/custom/arch/cc_windows.h deleted file mode 100755 index 30e478a..0000000 --- a/core/c/custom/arch/cc_windows.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef LWIP_ARCH_CC_H -#define LWIP_ARCH_CC_H - -#ifdef _MSC_VER -#pragma warning (disable: 4127) /* conditional expression is constant */ -#pragma warning (disable: 4996) /* 'strncpy' was declared deprecated */ -#pragma warning (disable: 4103) /* structure packing changed by including file */ -#pragma warning (disable: 4820) /* 'x' bytes padding added after data member 'y' */ -#pragma warning (disable: 4711) /* The compiler performed inlining on the given function, although it was not marked for inlining */ -#endif - -#define LWIP_PROVIDE_ERRNO - -/* Define platform endianness (might already be defined) */ -#ifndef BYTE_ORDER -#define BYTE_ORDER LITTLE_ENDIAN -#endif /* BYTE_ORDER */ - -typedef int sys_prot_t; - -#ifdef _MSC_VER -/* define _INTPTR for Win32 MSVC stdint.h */ -#define _INTPTR 2 - -/* Do not use lwIP default definitions for format strings - * because these do not work with MSVC 2010 compiler (no inttypes.h) - */ -#define LWIP_NO_INTTYPES_H 1 - -/* Define (sn)printf formatters for these lwIP types */ -#define X8_F "02x" -#define U16_F "hu" -#define U32_F "lu" -#define S32_F "ld" -#define X32_F "lx" - -#define S16_F "hd" -#define X16_F "hx" -#define SZT_F "lu" -#endif /* _MSC_VER */ - -/* Compiler hints for packing structures */ -#define PACK_STRUCT_USE_INCLUDES - -#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ - printf("Assertion \"%s\" failed at line %d in %s\n", message, __LINE__, __FILE__); \ - fflush(NULL);handler;} } while(0) - -#ifdef _MSC_VER -/* C runtime functions redefined */ -#define snprintf _snprintf -#define strdup _strdup -#endif - -/* Define an example for LWIP_PLATFORM_DIAG: since this uses varargs and the old - * C standard lwIP targets does not support this in macros, we have extra brackets - * around the arguments, which are left out in the following macro definition: - */ -#if !defined(LWIP_TESTMODE) || !LWIP_TESTMODE -void lwip_win32_platform_diag(const char *format, ...); -#define LWIP_PLATFORM_DIAG(x) lwip_win32_platform_diag x -#endif - -#ifndef LWIP_NORAND -extern unsigned int sys_win_rand(void); -#define LWIP_RAND() (sys_win_rand()) -#endif - -#define PPP_INCLUDE_SETTINGS_HEADER - -#endif /* LWIP_ARCH_CC_H */ diff --git a/core/c/custom/arch/epstruct.h b/core/c/custom/arch/epstruct.h deleted file mode 100755 index 7b11ffb..0000000 --- a/core/c/custom/arch/epstruct.h +++ /dev/null @@ -1 +0,0 @@ -#pragma pack(pop) diff --git a/core/c/custom/arch/perf.h b/core/c/custom/arch/perf.h deleted file mode 100755 index 1537016..0000000 --- a/core/c/custom/arch/perf.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef perf_h -#define perf_h - -#define PERF_START -#define PERF_STOP(x) - -#endif /* perf_h */ diff --git a/core/c/custom/arch/sys_arch.h b/core/c/custom/arch/sys_arch.h deleted file mode 100755 index cca4863..0000000 --- a/core/c/custom/arch/sys_arch.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __ARCH_SYS_ARCH_H__ -#define __ARCH_SYS_ARCH_H__ - -#define SYS_MBOX_NULL NULL -#define SYS_SEM_NULL NULL - -#endif /* __ARCH_SYS_ARCH_H__ */ diff --git a/core/c/custom/lwipopts.h b/core/c/custom/lwipopts.h deleted file mode 100755 index bbf9ef8..0000000 --- a/core/c/custom/lwipopts.h +++ /dev/null @@ -1,117 +0,0 @@ -/** - * @file lwipopts.h - * @author Ambroz Bizjak - * - * @section LICENSE - * - * 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 author 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 COPYRIGHT HOLDERS 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 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_CUSTOM_LWIPOPTS_H -#define LWIP_CUSTOM_LWIPOPTS_H - -// enable tun2socks logic -#define TUN2SOCKS 1 - -#define NO_SYS 1 -#define LWIP_TIMERS 1 - -#define IP_DEFAULT_TTL 64 -#define LWIP_ARP 0 -#define ARP_QUEUEING 0 -#define IP_FORWARD 0 -#define LWIP_ICMP 1 -#define LWIP_RAW 1 -#define LWIP_DHCP 0 -#define LWIP_AUTOIP 0 -#define LWIP_SNMP 0 -#define LWIP_IGMP 0 -#define LWIP_DNS 0 -#define LWIP_UDP 1 -#define LWIP_UDPLITE 0 -#define LWIP_TCP 1 -#define LWIP_CALLBACK_API 1 -#define LWIP_NETIF_API 0 -#define LWIP_NETIF_LOOPBACK 0 -#define LWIP_HAVE_LOOPIF 1 -#define LWIP_HAVE_SLIPIF 0 -#define LWIP_NETCONN 0 -#define LWIP_SOCKET 0 -#define PPP_SUPPORT 0 -#define LWIP_IPV6 1 -#define LWIP_IPV6_MLD 0 -#define LWIP_IPV6_AUTOCONFIG 1 - -// disable checksum checks -#define CHECKSUM_CHECK_IP 0 -#define CHECKSUM_CHECK_UDP 0 -#define CHECKSUM_CHECK_TCP 0 -#define CHECKSUM_CHECK_ICMP 0 -#define CHECKSUM_CHECK_ICMP6 0 - -#define LWIP_CHECKSUM_ON_COPY 1 - -#define MEMP_NUM_TCP_PCB_LISTEN 1 -#define MEMP_NUM_TCP_PCB 16 -#define MEMP_NUM_UDP_PCB 1 - -/* -#define TCP_LISTEN_BACKLOG 1 -#define TCP_DEFAULT_LISTEN_BACKLOG 0xff -#define LWIP_TCP_TIMESTAMPS 1 -*/ - -#define TCP_MSS 1460 -#define TCP_WND 32 * 1024 -#define TCP_SND_BUF (TCP_WND) - -#define MEM_LIBC_MALLOC 1 -#define MEMP_MEM_MALLOC 1 -#define MEM_SIZE 128 * 1024 - -#define SYS_LIGHTWEIGHT_PROT 0 -#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS - -// needed on 64-bit systems, enable it always so that the same configuration -// is used regardless of the platform -#define IPV6_FRAG_COPYHEADER 1 - -#define LWIP_DEBUG 0 -#define LWIP_DBG_TYPES_ON LWIP_DBG_OFF -#define INET_DEBUG LWIP_DBG_ON -#define IP_DEBUG LWIP_DBG_ON -#define RAW_DEBUG LWIP_DBG_ON -#define SYS_DEBUG LWIP_DBG_ON -#define NETIF_DEBUG LWIP_DBG_ON -#define TCP_DEBUG LWIP_DBG_ON -#define UDP_DEBUG LWIP_DBG_ON -#define TCP_INPUT_DEBUG LWIP_DBG_ON -#define TCP_OUTPUT_DEBUG LWIP_DBG_ON -#define TCPIP_DEBUG LWIP_DBG_ON -#define IP6_DEBUG LWIP_DBG_ON - -#define LWIP_STATS 0 -#define LWIP_STATS_DISPLAY 0 -#define LWIP_PERF 0 - -#endif diff --git a/core/c/custom/sys_arch.c b/core/c/custom/sys_arch.c deleted file mode 100755 index 49ae515..0000000 --- a/core/c/custom/sys_arch.c +++ /dev/null @@ -1,223 +0,0 @@ -#include "lwip/opt.h" -#include "lwip/sys.h" - -#ifdef _WIN32 - // defines both win32 and win64 - #ifdef _MSC_VER - #pragma warning (push, 3) - #endif - #include - #ifdef _MSC_VER - #pragma warning (pop) - #endif - #include - - #include - #include - #include - #include - - /** Set this to 1 to enable assertion checks that SYS_ARCH_PROTECT() is only - * called once in a call stack (calling it nested might cause trouble in some - * implementations, so let's avoid this in core code as long as we can). - */ - #ifndef LWIP_SYS_ARCH_CHECK_NESTED_PROTECT - #define LWIP_SYS_ARCH_CHECK_NESTED_PROTECT 1 - #endif - - /** Set this to 1 to enable assertion checks that SYS_ARCH_PROTECT() is *not* - * called before functions potentiolly involving the OS scheduler. - * - * This scheme is currently broken only for non-core-locking when waking up - * threads waiting on a socket via select/poll. - */ - #ifndef LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED - #define LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED LWIP_TCPIP_CORE_LOCKING - #endif - - #define LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER (LWIP_SYS_ARCH_CHECK_NESTED_PROTECT || LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED) - - /* These functions are used from NO_SYS also, for precise timer triggering */ - static LARGE_INTEGER freq, sys_start_time; - #define SYS_INITIALIZED() (freq.QuadPart != 0) - - static DWORD netconn_sem_tls_index; - - static HCRYPTPROV hcrypt; - - u32_t - sys_win_rand(void) - { - u32_t ret; - if (CryptGenRandom(hcrypt, sizeof(ret), (BYTE*)&ret)) { - return ret; - } - LWIP_ASSERT("CryptGenRandom failed", 0); - return 0; - } - - static void - sys_win_rand_init(void) - { - if (!CryptAcquireContext(&hcrypt, NULL, NULL, PROV_RSA_FULL, 0)) { - DWORD err = GetLastError(); - LWIP_PLATFORM_DIAG(("CryptAcquireContext failed with error %d, trying to create NEWKEYSET", (int)err)); - if(!CryptAcquireContext(&hcrypt, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { - char errbuf[128]; - err = GetLastError(); - snprintf(errbuf, sizeof(errbuf), "CryptAcquireContext failed with error %d", (int)err); - LWIP_UNUSED_ARG(err); - LWIP_ASSERT(errbuf, 0); - } - } - } - - static void - sys_init_timing(void) - { - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&sys_start_time); - } - - static LONGLONG - sys_get_ms_longlong(void) - { - LONGLONG ret; - LARGE_INTEGER now; - #if NO_SYS - if (!SYS_INITIALIZED()) { - sys_init(); - LWIP_ASSERT("initialization failed", SYS_INITIALIZED()); - } - #endif /* NO_SYS */ - QueryPerformanceCounter(&now); - ret = now.QuadPart-sys_start_time.QuadPart; - return (u32_t)(((ret)*1000)/freq.QuadPart); - } - - u32_t - sys_jiffies(void) - { - return (u32_t)sys_get_ms_longlong(); - } - - u32_t - sys_now(void) - { - return (u32_t)sys_get_ms_longlong(); - } - - CRITICAL_SECTION critSec; - #if LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER - static int protection_depth; - #endif - - static void - InitSysArchProtect(void) - { - InitializeCriticalSection(&critSec); - } - - sys_prot_t - sys_arch_protect(void) - { - #if NO_SYS - if (!SYS_INITIALIZED()) { - sys_init(); - LWIP_ASSERT("initialization failed", SYS_INITIALIZED()); - } - #endif - EnterCriticalSection(&critSec); - #if LWIP_SYS_ARCH_CHECK_NESTED_PROTECT - LWIP_ASSERT("nested SYS_ARCH_PROTECT", protection_depth == 0); - #endif - #if LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER - protection_depth++; - #endif - return 0; - } - - void - sys_arch_unprotect(sys_prot_t pval) - { - LWIP_UNUSED_ARG(pval); - #if LWIP_SYS_ARCH_CHECK_NESTED_PROTECT - LWIP_ASSERT("missing SYS_ARCH_PROTECT", protection_depth == 1); - #else - LWIP_ASSERT("missing SYS_ARCH_PROTECT", protection_depth > 0); - #endif - #if LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER - protection_depth--; - #endif - LeaveCriticalSection(&critSec); - } - - #if LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED - /** This checks that SYS_ARCH_PROTECT() hasn't been called by protecting - * and then checking the level - */ - static void - sys_arch_check_not_protected(void) - { - sys_arch_protect(); - LWIP_ASSERT("SYS_ARCH_PROTECT before scheduling", protection_depth == 1); - sys_arch_unprotect(0); - } - #else - #define sys_arch_check_not_protected() - #endif - - static void - msvc_sys_init(void) - { - sys_win_rand_init(); - sys_init_timing(); - InitSysArchProtect(); - netconn_sem_tls_index = TlsAlloc(); - LWIP_ASSERT("TlsAlloc failed", netconn_sem_tls_index != TLS_OUT_OF_INDEXES); - } - - void - sys_init(void) - { - msvc_sys_init(); - } - - #include - - /* This is an example implementation for LWIP_PLATFORM_DIAG: - * format a string and pass it to your output function. - */ - void - lwip_win32_platform_diag(const char *format, ...) - { - va_list ap; - /* get the varargs */ - va_start(ap, format); - /* print via varargs; to use another output function, you could use - vsnprintf here */ - vprintf(format, ap); - va_end(ap); - } -#elif __APPLE__ - #include - u32_t sys_now(void) { - uint64_t now = mach_absolute_time(); - mach_timebase_info_data_t info; - mach_timebase_info(&info); - now = now * info.numer / info.denom / NSEC_PER_MSEC; - return (u32_t)(now); - } -#elif __linux - #include - u32_t sys_now(void) - { - struct timeval te; - gettimeofday(&te, NULL); - return te.tv_sec*1000LL + te.tv_usec/1000; - } -#elif __unix // all unices not caught above - // Unix -#elif __posix - // POSIX -#endif diff --git a/core/c/include/compat/posix/arpa/inet.h b/core/c/include/compat/posix/arpa/inet.h deleted file mode 100755 index 68267e5..0000000 --- a/core/c/include/compat/posix/arpa/inet.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file - * This file is a posix wrapper for lwip/sockets.h. - */ - -/* - * 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/sockets.h" diff --git a/core/c/include/compat/posix/net/if.h b/core/c/include/compat/posix/net/if.h deleted file mode 100755 index a17e8ad..0000000 --- a/core/c/include/compat/posix/net/if.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @file - * This file is a posix wrapper for lwip/if_api.h. - */ - -/* - * Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. - * 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/if_api.h" diff --git a/core/c/include/compat/posix/netdb.h b/core/c/include/compat/posix/netdb.h deleted file mode 100755 index 29abbaf..0000000 --- a/core/c/include/compat/posix/netdb.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file - * This file is a posix wrapper for lwip/netdb.h. - */ - -/* - * 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/netdb.h" diff --git a/core/c/include/compat/posix/sys/socket.h b/core/c/include/compat/posix/sys/socket.h deleted file mode 100755 index 68267e5..0000000 --- a/core/c/include/compat/posix/sys/socket.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file - * This file is a posix wrapper for lwip/sockets.h. - */ - -/* - * 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/sockets.h" diff --git a/core/c/include/compat/stdc/errno.h b/core/c/include/compat/stdc/errno.h deleted file mode 100755 index a3bbfd2..0000000 --- a/core/c/include/compat/stdc/errno.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file - * This file is a posix/stdc wrapper for lwip/errno.h. - */ - -/* - * 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/errno.h" diff --git a/core/c/include/lwip/altcp.h b/core/c/include/lwip/altcp.h deleted file mode 100755 index 08bb8d5..0000000 --- a/core/c/include/lwip/altcp.h +++ /dev/null @@ -1,201 +0,0 @@ -/** - * @file - * Application layered TCP connection API (to be used from TCPIP thread)\n - * - * This file contains the generic API. - * For more details see @ref altcp_api. - */ - -/* - * Copyright (c) 2017 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ -#ifndef LWIP_HDR_ALTCP_H -#define LWIP_HDR_ALTCP_H - -#include "lwip/opt.h" - -#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/tcpbase.h" -#include "lwip/err.h" -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct altcp_pcb; -struct altcp_functions; - -typedef err_t (*altcp_accept_fn)(void *arg, struct altcp_pcb *new_conn, err_t err); -typedef err_t (*altcp_connected_fn)(void *arg, struct altcp_pcb *conn, err_t err); -typedef err_t (*altcp_recv_fn)(void *arg, struct altcp_pcb *conn, struct pbuf *p, err_t err); -typedef err_t (*altcp_sent_fn)(void *arg, struct altcp_pcb *conn, u16_t len); -typedef err_t (*altcp_poll_fn)(void *arg, struct altcp_pcb *conn); -typedef void (*altcp_err_fn)(void *arg, err_t err); - -typedef struct altcp_pcb* (*altcp_new_fn)(void *arg, u8_t ip_type); - -struct altcp_pcb { - const struct altcp_functions *fns; - struct altcp_pcb *inner_conn; - void *arg; - void *state; - /* application callbacks */ - altcp_accept_fn accept; - altcp_connected_fn connected; - altcp_recv_fn recv; - altcp_sent_fn sent; - altcp_poll_fn poll; - altcp_err_fn err; - u8_t pollinterval; -}; - -/** @ingroup altcp */ -typedef struct altcp_allocator_s { - /** Allocator function */ - altcp_new_fn alloc; - /** Argument to allocator function */ - void *arg; -} altcp_allocator_t; - -struct altcp_pcb *altcp_new(altcp_allocator_t *allocator); -struct altcp_pcb *altcp_new_ip6(altcp_allocator_t *allocator); -struct altcp_pcb *altcp_new_ip_type(altcp_allocator_t *allocator, u8_t ip_type); - -void altcp_arg(struct altcp_pcb *conn, void *arg); -void altcp_accept(struct altcp_pcb *conn, altcp_accept_fn accept); -void altcp_recv(struct altcp_pcb *conn, altcp_recv_fn recv); -void altcp_sent(struct altcp_pcb *conn, altcp_sent_fn sent); -void altcp_poll(struct altcp_pcb *conn, altcp_poll_fn poll, u8_t interval); -void altcp_err(struct altcp_pcb *conn, altcp_err_fn err); - -void altcp_recved(struct altcp_pcb *conn, u16_t len); -err_t altcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port); -err_t altcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected); - -/* return conn for source code compatibility to tcp callback API only */ -struct altcp_pcb *altcp_listen_with_backlog_and_err(struct altcp_pcb *conn, u8_t backlog, err_t *err); -#define altcp_listen_with_backlog(conn, backlog) altcp_listen_with_backlog_and_err(conn, backlog, NULL) -/** @ingroup altcp */ -#define altcp_listen(conn) altcp_listen_with_backlog_and_err(conn, TCP_DEFAULT_LISTEN_BACKLOG, NULL) - -void altcp_abort(struct altcp_pcb *conn); -err_t altcp_close(struct altcp_pcb *conn); -err_t altcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx); - -err_t altcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags); -err_t altcp_output(struct altcp_pcb *conn); - -u16_t altcp_mss(struct altcp_pcb *conn); -u16_t altcp_sndbuf(struct altcp_pcb *conn); -u16_t altcp_sndqueuelen(struct altcp_pcb *conn); -void altcp_nagle_disable(struct altcp_pcb *conn); -void altcp_nagle_enable(struct altcp_pcb *conn); -int altcp_nagle_disabled(struct altcp_pcb *conn); - -void altcp_setprio(struct altcp_pcb *conn, u8_t prio); - -err_t altcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port); -ip_addr_t *altcp_get_ip(struct altcp_pcb *conn, int local); -u16_t altcp_get_port(struct altcp_pcb *conn, int local); - -#ifdef LWIP_DEBUG -enum tcp_state altcp_dbg_get_tcp_state(struct altcp_pcb *conn); -#endif - -#ifdef __cplusplus -} -#endif - -#else /* LWIP_ALTCP */ - -/* ALTCP disabled, define everything to link against tcp callback API (e.g. to get a small non-ssl httpd) */ - -#include "lwip/tcp.h" - -#define altcp_accept_fn tcp_accept_fn -#define altcp_connected_fn tcp_connected_fn -#define altcp_recv_fn tcp_recv_fn -#define altcp_sent_fn tcp_sent_fn -#define altcp_poll_fn tcp_poll_fn -#define altcp_err_fn tcp_err_fn - -#define altcp_pcb tcp_pcb -#define altcp_tcp_new_ip_type tcp_new_ip_type -#define altcp_tcp_new tcp_new -#define altcp_tcp_new_ip6 tcp_new_ip6 - -#define altcp_new(allocator) tcp_new() -#define altcp_new_ip6(allocator) tcp_new_ip6() -#define altcp_new_ip_type(allocator, ip_type) tcp_new_ip_type(ip_type) - -#define altcp_arg tcp_arg -#define altcp_accept tcp_accept -#define altcp_recv tcp_recv -#define altcp_sent tcp_sent -#define altcp_poll tcp_poll -#define altcp_err tcp_err - -#define altcp_recved tcp_recved -#define altcp_bind tcp_bind -#define altcp_connect tcp_connect - -#define altcp_listen_with_backlog_and_err tcp_listen_with_backlog_and_err -#define altcp_listen_with_backlog tcp_listen_with_backlog -#define altcp_listen tcp_listen - -#define altcp_abort tcp_abort -#define altcp_close tcp_close -#define altcp_shutdown tcp_shutdown - -#define altcp_write tcp_write -#define altcp_output tcp_output - -#define altcp_mss tcp_mss -#define altcp_sndbuf tcp_sndbuf -#define altcp_sndqueuelen tcp_sndqueuelen -#define altcp_nagle_disable tcp_nagle_disable -#define altcp_nagle_enable tcp_nagle_enable -#define altcp_nagle_disabled tcp_nagle_disabled -#define altcp_setprio tcp_setprio - -#define altcp_get_tcp_addrinfo tcp_get_tcp_addrinfo -#define altcp_get_ip(pcb, local) ((local) ? (&(pcb)->local_ip) : (&(pcb)->remote_ip)) - -#ifdef LWIP_DEBUG -#define altcp_dbg_get_tcp_state tcp_dbg_get_tcp_state -#endif - -#endif /* LWIP_ALTCP */ - -#endif /* LWIP_HDR_ALTCP_H */ diff --git a/core/c/include/lwip/altcp_tcp.h b/core/c/include/lwip/altcp_tcp.h deleted file mode 100755 index 53550c7..0000000 --- a/core/c/include/lwip/altcp_tcp.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file - * Application layered TCP connection API (to be used from TCPIP thread)\n - * This interface mimics the tcp callback API to the application while preventing - * direct linking (much like virtual functions). - * This way, an application can make use of other application layer protocols - * on top of TCP without knowing the details (e.g. TLS, proxy connection). - * - * This file contains the base implementation calling into tcp. - */ - -/* - * Copyright (c) 2017 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ -#ifndef LWIP_HDR_ALTCP_TCP_H -#define LWIP_HDR_ALTCP_TCP_H - -#include "lwip/opt.h" - -#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/altcp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct altcp_pcb *altcp_tcp_new_ip_type(u8_t ip_type); - -#define altcp_tcp_new() altcp_tcp_new_ip_type(IPADDR_TYPE_V4) -#define altcp_tcp_new_ip6() altcp_tcp_new_ip_type(IPADDR_TYPE_V6) - -struct altcp_pcb *altcp_tcp_alloc(void *arg, u8_t ip_type); - -struct tcp_pcb; -struct altcp_pcb *altcp_tcp_wrap(struct tcp_pcb *tpcb); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_ALTCP */ - -#endif /* LWIP_HDR_ALTCP_TCP_H */ diff --git a/core/c/include/lwip/altcp_tls.h b/core/c/include/lwip/altcp_tls.h deleted file mode 100755 index c5a6820..0000000 --- a/core/c/include/lwip/altcp_tls.h +++ /dev/null @@ -1,117 +0,0 @@ -/** - * @file - * Application layered TCP/TLS connection API (to be used from TCPIP thread) - * - * @defgroup altcp_tls TLS layer - * @ingroup altcp - * This file contains function prototypes for a TLS layer. - * A port to ARM mbedtls is provided in the apps/ tree - * (LWIP_ALTCP_TLS_MBEDTLS option). - */ - -/* - * Copyright (c) 2017 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ -#ifndef LWIP_HDR_ALTCP_TLS_H -#define LWIP_HDR_ALTCP_TLS_H - -#include "lwip/opt.h" - -#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ - -#if LWIP_ALTCP_TLS - -#include "lwip/altcp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** @ingroup altcp_tls - * ALTCP_TLS configuration handle, content depends on port (e.g. mbedtls) - */ -struct altcp_tls_config; - -/** @ingroup altcp_tls - * Create an ALTCP_TLS server configuration handle - */ -struct altcp_tls_config *altcp_tls_create_config_server_privkey_cert(const u8_t *privkey, size_t privkey_len, - const u8_t *privkey_pass, size_t privkey_pass_len, - const u8_t *cert, size_t cert_len); - -/** @ingroup altcp_tls - * Create an ALTCP_TLS client configuration handle - */ -struct altcp_tls_config *altcp_tls_create_config_client(const u8_t *cert, size_t cert_len); - -/** @ingroup altcp_tls - * Create an ALTCP_TLS client configuration handle with two-way server/client authentication - */ -struct altcp_tls_config *altcp_tls_create_config_client_2wayauth(const u8_t *ca, size_t ca_len, const u8_t *privkey, size_t privkey_len, - const u8_t *privkey_pass, size_t privkey_pass_len, - const u8_t *cert, size_t cert_len); - -/** @ingroup altcp_tls - * Free an ALTCP_TLS configuration handle - */ -void altcp_tls_free_config(struct altcp_tls_config *conf); - -/** @ingroup altcp_tls - * Create new ALTCP_TLS layer wrapping an existing pcb as inner connection (e.g. TLS over TCP) - */ -struct altcp_pcb *altcp_tls_wrap(struct altcp_tls_config *config, struct altcp_pcb *inner_pcb); - -/** @ingroup altcp_tls - * Create new ALTCP_TLS pcb and its inner tcp pcb - */ -struct altcp_pcb *altcp_tls_new(struct altcp_tls_config *config, u8_t ip_type); - -/** @ingroup altcp_tls - * Create new ALTCP_TLS layer pcb and its inner tcp pcb. - * Same as @ref altcp_tls_new but this allocator function fits to - * @ref altcp_allocator_t / @ref altcp_new.\n - 'arg' must contain a struct altcp_tls_config *. - */ -struct altcp_pcb *altcp_tls_alloc(void *arg, u8_t ip_type); - -/** @ingroup altcp_tls - * Return pointer to internal TLS context so application can tweak it. - * Real type depends on port (e.g. mbedtls) - */ -void *altcp_tls_context(struct altcp_pcb *conn); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_ALTCP_TLS */ -#endif /* LWIP_ALTCP */ -#endif /* LWIP_HDR_ALTCP_TLS_H */ diff --git a/core/c/include/lwip/api.h b/core/c/include/lwip/api.h deleted file mode 100755 index eca6ac2..0000000 --- a/core/c/include/lwip/api.h +++ /dev/null @@ -1,431 +0,0 @@ -/** - * @file - * netconn API (to be used from non-TCPIP threads) - */ - -/* - * 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_HDR_API_H -#define LWIP_HDR_API_H - -#include "lwip/opt.h" - -#if LWIP_NETCONN || LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ -/* Note: Netconn API is always available when sockets are enabled - - * sockets are implemented on top of them */ - -#include "lwip/arch.h" -#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 -#define NETCONN_NOAUTORCVD 0x08 /* prevent netconn_recv_data_tcp() from updating the tcp window - must be done manually via netconn_tcp_recvd() */ -#define NETCONN_NOFIN 0x10 /* upper layer already received data, leave FIN in queue until called again */ - -/* Flags for struct netconn.flags (u8_t) */ -/** This netconn had an error, don't block on recvmbox/acceptmbox any more */ -#define NETCONN_FLAG_MBOXCLOSED 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 LWIP_NETCONN_FULLDUPLEX - /** The mbox of this netconn is being deallocated, don't use it anymore */ -#define NETCONN_FLAG_MBOXINVALID 0x08 -#endif /* LWIP_NETCONN_FULLDUPLEX */ -/** 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 -#if LWIP_IPV6 -/** If this flag is set then only IPv6 communication is allowed on the - netconn. As per RFC#3493 this features defaults to OFF allowing - dual-stack usage by default. */ -#define NETCONN_FLAG_IPV6_V6ONLY 0x20 -#endif /* LWIP_IPV6 */ -#if LWIP_NETBUF_RECVINFO -/** Received packet info will be recorded for this netconn */ -#define NETCONN_FLAG_PKTINFO 0x40 -#endif /* LWIP_NETBUF_RECVINFO */ -/** A FIN has been received but not passed to the application yet */ -#define NETCONN_FIN_RX_PENDING 0x80 - -/* Helpers to process several netconn_types by the same code */ -#define NETCONNTYPE_GROUP(t) ((t)&0xF0) -#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0) -#if LWIP_IPV6 -#define NETCONN_TYPE_IPV6 0x08 -#define NETCONNTYPE_ISIPV6(t) (((t)&NETCONN_TYPE_IPV6) != 0) -#define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF3) == NETCONN_UDPLITE) -#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF3) == NETCONN_UDPNOCHKSUM) -#else /* LWIP_IPV6 */ -#define NETCONNTYPE_ISIPV6(t) (0) -#define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE) -#define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM) -#endif /* LWIP_IPV6 */ - -/** @ingroup netconn_common - * Protocol family and type of the netconn - */ -enum netconn_type { - NETCONN_INVALID = 0, - /** TCP IPv4 */ - NETCONN_TCP = 0x10, -#if LWIP_IPV6 - /** TCP IPv6 */ - NETCONN_TCP_IPV6 = NETCONN_TCP | NETCONN_TYPE_IPV6 /* 0x18 */, -#endif /* LWIP_IPV6 */ - /** UDP IPv4 */ - NETCONN_UDP = 0x20, - /** UDP IPv4 lite */ - NETCONN_UDPLITE = 0x21, - /** UDP IPv4 no checksum */ - NETCONN_UDPNOCHKSUM = 0x22, - -#if LWIP_IPV6 - /** UDP IPv6 (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ - NETCONN_UDP_IPV6 = NETCONN_UDP | NETCONN_TYPE_IPV6 /* 0x28 */, - /** UDP IPv6 lite (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ - NETCONN_UDPLITE_IPV6 = NETCONN_UDPLITE | NETCONN_TYPE_IPV6 /* 0x29 */, - /** UDP IPv6 no checksum (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ - NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */, -#endif /* LWIP_IPV6 */ - - /** Raw connection IPv4 */ - NETCONN_RAW = 0x40 -#if LWIP_IPV6 - /** Raw connection IPv6 (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ - , NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */ -#endif /* LWIP_IPV6 */ -}; - -/** Current state of the netconn. Non-TCP netconns are always - * in state NETCONN_NONE! */ -enum netconn_state { - NETCONN_NONE, - NETCONN_WRITE, - NETCONN_LISTEN, - NETCONN_CONNECT, - NETCONN_CLOSE -}; - -/** Used to inform the callback function about changes - * - * Event explanation: - * - * In the netconn implementation, there are three ways to block a client: - * - * - accept mbox (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); in netconn_accept()) - * - receive mbox (sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); in netconn_recv_data()) - * - send queue is full (sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); in lwip_netconn_do_write()) - * - * The events have to be seen as events signaling the state of these mboxes/semaphores. For non-blocking - * connections, you need to know in advance whether a call to a netconn function call would block or not, - * and these events tell you about that. - * - * RCVPLUS events say: Safe to perform a potentially blocking call call once more. - * They are counted in sockets - three RCVPLUS events for accept mbox means you are safe - * to call netconn_accept 3 times without being blocked. - * Same thing for receive mbox. - * - * RCVMINUS events say: Your call to to a possibly blocking function is "acknowledged". - * Socket implementation decrements the counter. - * - * For TX, there is no need to count, its merely a flag. SENDPLUS means you may send something. - * SENDPLUS occurs when enough data was delivered to peer so netconn_send() can be called again. - * A SENDMINUS event occurs when the next call to a netconn_send() would be blocking. - */ -enum netconn_evt { - NETCONN_EVT_RCVPLUS, - NETCONN_EVT_RCVMINUS, - NETCONN_EVT_SENDPLUS, - NETCONN_EVT_SENDMINUS, - NETCONN_EVT_ERROR -}; - -#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) -/** Used for netconn_join_leave_group() */ -enum netconn_igmp { - NETCONN_JOIN, - NETCONN_LEAVE -}; -#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ - -#if LWIP_DNS -/* Used for netconn_gethostbyname_addrtype(), these should match the DNS_ADDRTYPE defines in dns.h */ -#define NETCONN_DNS_DEFAULT NETCONN_DNS_IPV4_IPV6 -#define NETCONN_DNS_IPV4 0 -#define NETCONN_DNS_IPV6 1 -#define NETCONN_DNS_IPV4_IPV6 2 /* try to resolve IPv4 first, try IPv6 if IPv4 fails only */ -#define NETCONN_DNS_IPV6_IPV4 3 /* try to resolve IPv6 first, try IPv4 if IPv6 fails only */ -#endif /* LWIP_DNS */ - -/* 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; - -/** 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 asynchronous unreported error this netconn had */ - err_t pending_err; -#if !LWIP_NETCONN_SEM_PER_THREAD - /** sem that is used to synchronously execute functions in the core context */ - sys_sem_t op_completed; -#endif - /** 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 */ -#if LWIP_NETCONN_FULLDUPLEX - /** number of threads waiting on an mbox. This is required to unblock - all threads when closing while threads are waiting. */ - int mbox_threads_waiting; -#endif - /** only used for socket layer */ -#if LWIP_SOCKET - int socket; -#endif /* LWIP_SOCKET */ -#if LWIP_SO_SNDTIMEO - /** timeout to wait for sending data (which means enqueueing data for sending - in internal buffers) in milliseconds */ - s32_t send_timeout; -#endif /* LWIP_SO_RCVTIMEO */ -#if LWIP_SO_RCVTIMEO - /** timeout in milliseconds to wait for new data to be received - (or connections to arrive for listening netconns) */ - u32_t 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 */ - int recv_avail; -#endif /* LWIP_SO_RCVBUF */ -#if LWIP_SO_LINGER - /** values <0 mean linger is disabled, values > 0 are seconds to linger */ - s16_t linger; -#endif /* LWIP_SO_LINGER */ - /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ - u8_t flags; -#if LWIP_TCP - /** TCP: when data passed to netconn_write doesn't fit into the send buffer, - this temporarily stores the message. - Also used during connect and close. */ - struct api_msg *current_msg; -#endif /* LWIP_TCP */ - /** A callback function that is informed about events for this netconn */ - netconn_callback callback; -}; - -/** This vector type is passed to @ref netconn_write_vectors_partly to send - * multiple buffers at once. - * ATTENTION: This type has to directly map struct iovec since one is casted - * into the other! - */ -struct netvector { - /** pointer to the application buffer that contains the data to send */ - const void *ptr; - /** size of the application data to send */ - size_t len; -}; - -/** Register an Network connection event */ -#define API_EVENT(c,e,l) if (c->callback) { \ - (*c->callback)(c, e, l); \ - } - -/* Network connection functions: */ - -/** @ingroup netconn_common - * Create new netconn connection - * @param t @ref netconn_type */ -#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_prepare_delete(struct netconn *conn); -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); -/** @ingroup netconn_common */ -#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) -/** @ingroup netconn_common */ -#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) - -err_t netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port); -err_t netconn_bind_if(struct netconn *conn, u8_t if_idx); -err_t netconn_connect(struct netconn *conn, const 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); -/** @ingroup netconn_tcp */ -#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_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf); -err_t netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags); -err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); -err_t netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags); -err_t netconn_tcp_recvd(struct netconn *conn, size_t len); -err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, - const ip_addr_t *addr, u16_t port); -err_t netconn_send(struct netconn *conn, struct netbuf *buf); -err_t netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, - u8_t apiflags, size_t *bytes_written); -err_t netconn_write_vectors_partly(struct netconn *conn, struct netvector *vectors, u16_t vectorcnt, - u8_t apiflags, size_t *bytes_written); -/** @ingroup netconn_tcp */ -#define netconn_write(conn, dataptr, size, apiflags) \ - netconn_write_partly(conn, dataptr, size, apiflags, NULL) -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 || (LWIP_IPV6 && LWIP_IPV6_MLD) -err_t netconn_join_leave_group(struct netconn *conn, const ip_addr_t *multiaddr, - const ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); -err_t netconn_join_leave_group_netif(struct netconn *conn, const ip_addr_t *multiaddr, - u8_t if_idx, enum netconn_igmp join_or_leave); -#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ -#if LWIP_DNS -#if LWIP_IPV4 && LWIP_IPV6 -err_t netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype); -#define netconn_gethostbyname(name, addr) netconn_gethostbyname_addrtype(name, addr, NETCONN_DNS_DEFAULT) -#else /* LWIP_IPV4 && LWIP_IPV6 */ -err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); -#define netconn_gethostbyname_addrtype(name, addr, dns_addrtype) netconn_gethostbyname(name, addr) -#endif /* LWIP_IPV4 && LWIP_IPV6 */ -#endif /* LWIP_DNS */ - -err_t netconn_err(struct netconn *conn); -#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) - -#define netconn_set_flags(conn, set_flags) do { (conn)->flags = (u8_t)((conn)->flags | (set_flags)); } while(0) -#define netconn_clear_flags(conn, clr_flags) do { (conn)->flags = (u8_t)((conn)->flags & (u8_t)(~(clr_flags) & 0xff)); } while(0) -#define netconn_is_flag_set(conn, flag) (((conn)->flags & (flag)) != 0) - -/** Set the blocking status of netconn calls (@todo: write/send is missing) */ -#define netconn_set_nonblocking(conn, val) do { if(val) { \ - netconn_set_flags(conn, NETCONN_FLAG_NON_BLOCKING); \ -} else { \ - netconn_clear_flags(conn, 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) - -#if LWIP_IPV6 -/** @ingroup netconn_common - * TCP: Set the IPv6 ONLY status of netconn calls (see NETCONN_FLAG_IPV6_V6ONLY) - */ -#define netconn_set_ipv6only(conn, val) do { if(val) { \ - netconn_set_flags(conn, NETCONN_FLAG_IPV6_V6ONLY); \ -} else { \ - netconn_clear_flags(conn, NETCONN_FLAG_IPV6_V6ONLY); }} while(0) -/** @ingroup netconn_common - * TCP: Get the IPv6 ONLY status of netconn calls (see NETCONN_FLAG_IPV6_V6ONLY) - */ -#define netconn_get_ipv6only(conn) (((conn)->flags & NETCONN_FLAG_IPV6_V6ONLY) != 0) -#endif /* LWIP_IPV6 */ - -#if LWIP_SO_SNDTIMEO -/** Set the send timeout in milliseconds */ -#define netconn_set_sendtimeout(conn, timeout) ((conn)->send_timeout = (timeout)) -/** Get the send timeout in milliseconds */ -#define netconn_get_sendtimeout(conn) ((conn)->send_timeout) -#endif /* LWIP_SO_SNDTIMEO */ -#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*/ - -#if LWIP_NETCONN_SEM_PER_THREAD -void netconn_thread_init(void); -void netconn_thread_cleanup(void); -#else /* LWIP_NETCONN_SEM_PER_THREAD */ -#define netconn_thread_init() -#define netconn_thread_cleanup() -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_NETCONN || LWIP_SOCKET */ - -#endif /* LWIP_HDR_API_H */ diff --git a/core/c/include/lwip/apps/FILES b/core/c/include/lwip/apps/FILES deleted file mode 100755 index c983076..0000000 --- a/core/c/include/lwip/apps/FILES +++ /dev/null @@ -1,2 +0,0 @@ -This directory contains application headers. -Every application shall provide one api file APP.h and optionally one options file APP_opts.h diff --git a/core/c/include/lwip/apps/altcp_proxyconnect.h b/core/c/include/lwip/apps/altcp_proxyconnect.h deleted file mode 100755 index a7c3527..0000000 --- a/core/c/include/lwip/apps/altcp_proxyconnect.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file - * Application layered TCP connection API that executes a proxy-connect. - * - * This file provides a starting layer that executes a proxy-connect e.g. to - * set up TLS connections through a http proxy. - */ - -/* - * Copyright (c) 2018 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ - -#ifndef LWIP_HDR_APPS_ALTCP_PROXYCONNECT_H -#define LWIP_HDR_APPS_ALTCP_PROXYCONNECT_H - -#include "lwip/opt.h" - -#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/ip_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct altcp_proxyconnect_config { - ip_addr_t proxy_addr; - u16_t proxy_port; -}; - - -struct altcp_pcb *altcp_proxyconnect_new(struct altcp_proxyconnect_config *config, struct altcp_pcb *inner_pcb); -struct altcp_pcb *altcp_proxyconnect_new_tcp(struct altcp_proxyconnect_config *config, u8_t ip_type); - -struct altcp_pcb *altcp_proxyconnect_alloc(void *arg, u8_t ip_type); - -#if LWIP_ALTCP_TLS -struct altcp_proxyconnect_tls_config { - struct altcp_proxyconnect_config proxy; - struct altcp_tls_config *tls_config; -}; - -struct altcp_pcb *altcp_proxyconnect_tls_alloc(void *arg, u8_t ip_type); -#endif /* LWIP_ALTCP_TLS */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_ALTCP */ -#endif /* LWIP_HDR_APPS_ALTCP_PROXYCONNECT_H */ diff --git a/core/c/include/lwip/apps/altcp_tls_mbedtls_opts.h b/core/c/include/lwip/apps/altcp_tls_mbedtls_opts.h deleted file mode 100755 index 63f72e3..0000000 --- a/core/c/include/lwip/apps/altcp_tls_mbedtls_opts.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file - * Application layered TCP/TLS connection API (to be used from TCPIP thread) - * - * This file contains options for an mbedtls port of the TLS layer. - */ - -/* - * Copyright (c) 2017 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ -#ifndef LWIP_HDR_ALTCP_TLS_OPTS_H -#define LWIP_HDR_ALTCP_TLS_OPTS_H - -#include "lwip/opt.h" - -#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ - -/** LWIP_ALTCP_TLS_MBEDTLS==1: use mbedTLS for TLS support for altcp API - * mbedtls include directory must be reachable via include search path - */ -#ifndef LWIP_ALTCP_TLS_MBEDTLS -#define LWIP_ALTCP_TLS_MBEDTLS 0 -#endif - -/** Configure debug level of this file */ -#ifndef ALTCP_MBEDTLS_DEBUG -#define ALTCP_MBEDTLS_DEBUG LWIP_DBG_OFF -#endif - -/** Set a session timeout in seconds for the basic session cache - * ATTENTION: Using a session cache can lower security by reusing keys! - */ -#ifndef ALTCP_MBEDTLS_SESSION_CACHE_TIMEOUT_SECONDS -#define ALTCP_MBEDTLS_SESSION_CACHE_TIMEOUT_SECONDS 0 -#endif - -#endif /* LWIP_ALTCP */ - -#endif /* LWIP_HDR_ALTCP_TLS_OPTS_H */ diff --git a/core/c/include/lwip/apps/fs.h b/core/c/include/lwip/apps/fs.h deleted file mode 100755 index 02bde1f..0000000 --- a/core/c/include/lwip/apps/fs.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef LWIP_HDR_APPS_FS_H -#define LWIP_HDR_APPS_FS_H - -#include "httpd_opts.h" -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define FS_READ_EOF -1 -#define FS_READ_DELAYED -2 - -#if HTTPD_PRECALCULATED_CHECKSUM -struct fsdata_chksum { - u32_t offset; - u16_t chksum; - u16_t len; -}; -#endif /* HTTPD_PRECALCULATED_CHECKSUM */ - -#define FS_FILE_FLAGS_HEADER_INCLUDED 0x01 -#define FS_FILE_FLAGS_HEADER_PERSISTENT 0x02 -#define FS_FILE_FLAGS_HEADER_HTTPVER_1_1 0x04 -#define FS_FILE_FLAGS_SSI 0x08 - -/** Define FS_FILE_EXTENSION_T_DEFINED if you have typedef'ed to your private - * pointer type (defaults to 'void' so the default usage is 'void*') - */ -#ifndef FS_FILE_EXTENSION_T_DEFINED -typedef void fs_file_extension; -#endif - -struct fs_file { - const char *data; - int len; - int index; - /* pextension is free for implementations to hold private (extensional) - arbitrary data, e.g. holding some file state or file system handle */ - fs_file_extension *pextension; -#if HTTPD_PRECALCULATED_CHECKSUM - const struct fsdata_chksum *chksum; - u16_t chksum_count; -#endif /* HTTPD_PRECALCULATED_CHECKSUM */ - u8_t flags; -#if LWIP_HTTPD_CUSTOM_FILES - u8_t is_custom_file; -#endif /* LWIP_HTTPD_CUSTOM_FILES */ -#if LWIP_HTTPD_FILE_STATE - void *state; -#endif /* LWIP_HTTPD_FILE_STATE */ -}; - -#if LWIP_HTTPD_FS_ASYNC_READ -typedef void (*fs_wait_cb)(void *arg); -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ - -err_t fs_open(struct fs_file *file, const char *name); -void fs_close(struct fs_file *file); -#if LWIP_HTTPD_DYNAMIC_FILE_READ -#if LWIP_HTTPD_FS_ASYNC_READ -int fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg); -#else /* LWIP_HTTPD_FS_ASYNC_READ */ -int fs_read(struct fs_file *file, char *buffer, int count); -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ -#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ -#if LWIP_HTTPD_FS_ASYNC_READ -int fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg); -#endif /* LWIP_HTTPD_FS_ASYNC_READ */ -int fs_bytes_left(struct fs_file *file); - -#if LWIP_HTTPD_FILE_STATE -/** This user-defined function is called when a file is opened. */ -void *fs_state_init(struct fs_file *file, const char *name); -/** This user-defined function is called when a file is closed. */ -void fs_state_free(struct fs_file *file, void *state); -#endif /* #if LWIP_HTTPD_FILE_STATE */ - -struct fsdata_file { - const struct fsdata_file *next; - const unsigned char *name; - const unsigned char *data; - int len; - u8_t flags; -#if HTTPD_PRECALCULATED_CHECKSUM - u16_t chksum_count; - const struct fsdata_chksum *chksum; -#endif /* HTTPD_PRECALCULATED_CHECKSUM */ -}; - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_FS_H */ diff --git a/core/c/include/lwip/apps/http_client.h b/core/c/include/lwip/apps/http_client.h deleted file mode 100755 index f4754b3..0000000 --- a/core/c/include/lwip/apps/http_client.h +++ /dev/null @@ -1,160 +0,0 @@ -/** - * @file - * HTTP client - */ - -/* - * Copyright (c) 2018 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ - -#ifndef LWIP_HDR_APPS_HTTP_CLIENT_H -#define LWIP_HDR_APPS_HTTP_CLIENT_H - -#include "lwip/opt.h" -#include "lwip/ip_addr.h" -#include "lwip/err.h" -#include "lwip/altcp.h" -#include "lwip/prot/iana.h" -#include "lwip/pbuf.h" - -#if LWIP_TCP && LWIP_CALLBACK_API - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @ingroup httpc - * HTTPC_HAVE_FILE_IO: define this to 1 to have functions dowloading directly - * to disk via fopen/fwrite. - * These functions are example implementations of the interface only. - */ -#ifndef LWIP_HTTPC_HAVE_FILE_IO -#define LWIP_HTTPC_HAVE_FILE_IO 0 -#endif - -/** - * @ingroup httpc - * The default TCP port used for HTTP - */ -#define HTTP_DEFAULT_PORT LWIP_IANA_PORT_HTTP - -/** - * @ingroup httpc - * HTTP client result codes - */ -typedef enum ehttpc_result { - /** File successfully received */ - HTTPC_RESULT_OK = 0, - /** Unknown error */ - HTTPC_RESULT_ERR_UNKNOWN = 1, - /** Connection to server failed */ - HTTPC_RESULT_ERR_CONNECT = 2, - /** Failed to resolve server hostname */ - HTTPC_RESULT_ERR_HOSTNAME = 3, - /** Connection unexpectedly closed by remote server */ - HTTPC_RESULT_ERR_CLOSED = 4, - /** Connection timed out (server didn't respond in time) */ - HTTPC_RESULT_ERR_TIMEOUT = 5, - /** Server responded with an error code */ - HTTPC_RESULT_ERR_SVR_RESP = 6, - /** Local memory error */ - HTTPC_RESULT_ERR_MEM = 7, - /** Local abort */ - HTTPC_RESULT_LOCAL_ABORT = 8, - /** Content length mismatch */ - HTTPC_RESULT_ERR_CONTENT_LEN = 9 -} httpc_result_t; - -typedef struct _httpc_state httpc_state_t; - -/** - * @ingroup httpc - * Prototype of a http client callback function - * - * @param arg argument specified when initiating the request - * @param httpc_result result of the http transfer (see enum httpc_result_t) - * @param rx_content_len number of bytes received (without headers) - * @param srv_res this contains the http status code received (if any) - * @param err an error returned by internal lwip functions, can help to specify - * the source of the error but must not necessarily be != ERR_OK - */ -typedef void (*httpc_result_fn)(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err); - -/** - * @ingroup httpc - * Prototype of http client callback: called when the headers are received - * - * @param connection http client connection - * @param arg argument specified when initiating the request - * @param hdr header pbuf(s) (may contain data also) - * @param hdr_len length of the heders in 'hdr' - * @param content_len content length as received in the headers (-1 if not received) - * @return if != ERR_OK is returned, the connection is aborted - */ -typedef err_t (*httpc_headers_done_fn)(httpc_state_t *connection, void *arg, struct pbuf *hdr, u16_t hdr_len, u32_t content_len); - -typedef struct _httpc_connection { - ip_addr_t proxy_addr; - u16_t proxy_port; - u8_t use_proxy; - /* @todo: add username:pass? */ - -#if LWIP_ALTCP - altcp_allocator_t *altcp_allocator; -#endif - - /* this callback is called when the transfer is finished (or aborted) */ - httpc_result_fn result_fn; - /* this callback is called after receiving the http headers - It can abort the connection by returning != ERR_OK */ - httpc_headers_done_fn headers_done_fn; -} httpc_connection_t; - -err_t httpc_get_file(const ip_addr_t* server_addr, u16_t port, const char* uri, const httpc_connection_t *settings, - altcp_recv_fn recv_fn, void* callback_arg, httpc_state_t **connection); -err_t httpc_get_file_dns(const char* server_name, u16_t port, const char* uri, const httpc_connection_t *settings, - altcp_recv_fn recv_fn, void* callback_arg, httpc_state_t **connection); - -#if LWIP_HTTPC_HAVE_FILE_IO -err_t httpc_get_file_to_disk(const ip_addr_t* server_addr, u16_t port, const char* uri, const httpc_connection_t *settings, - void* callback_arg, const char* local_file_name, httpc_state_t **connection); -err_t httpc_get_file_dns_to_disk(const char* server_name, u16_t port, const char* uri, const httpc_connection_t *settings, - void* callback_arg, const char* local_file_name, httpc_state_t **connection); -#endif /* LWIP_HTTPC_HAVE_FILE_IO */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_TCP && LWIP_CALLBACK_API */ - -#endif /* LWIP_HDR_APPS_HTTP_CLIENT_H */ diff --git a/core/c/include/lwip/apps/httpd.h b/core/c/include/lwip/apps/httpd.h deleted file mode 100755 index 615261e..0000000 --- a/core/c/include/lwip/apps/httpd.h +++ /dev/null @@ -1,255 +0,0 @@ -/** - * @file - * HTTP server - */ - -/* - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - * This version of the file has been modified by Texas Instruments to offer - * simple server-side-include (SSI) and Common Gateway Interface (CGI) - * capability. - */ - -#ifndef LWIP_HDR_APPS_HTTPD_H -#define LWIP_HDR_APPS_HTTPD_H - -#include "httpd_opts.h" -#include "lwip/err.h" -#include "lwip/pbuf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_HTTPD_CGI - -/** - * @ingroup httpd - * Function pointer for a CGI script handler. - * - * This function is called each time the HTTPD server is asked for a file - * whose name was previously registered as a CGI function using a call to - * http_set_cgi_handlers. The iIndex parameter provides the index of the - * CGI within the cgis array passed to http_set_cgi_handlers. Parameters - * pcParam and pcValue provide access to the parameters provided along with - * the URI. iNumParams provides a count of the entries in the pcParam and - * pcValue arrays. Each entry in the pcParam array contains the name of a - * parameter with the corresponding entry in the pcValue array containing the - * value for that parameter. Note that pcParam may contain multiple elements - * with the same name if, for example, a multi-selection list control is used - * in the form generating the data. - * - * The function should return a pointer to a character string which is the - * path and filename of the response that is to be sent to the connected - * browser, for example "/thanks.htm" or "/response/error.ssi". - * - * The maximum number of parameters that will be passed to this function via - * iNumParams is defined by LWIP_HTTPD_MAX_CGI_PARAMETERS. Any parameters in - * the incoming HTTP request above this number will be discarded. - * - * Requests intended for use by this CGI mechanism must be sent using the GET - * method (which encodes all parameters within the URI rather than in a block - * later in the request). Attempts to use the POST method will result in the - * request being ignored. - * - */ -typedef const char *(*tCGIHandler)(int iIndex, int iNumParams, char *pcParam[], - char *pcValue[]); - -/** - * @ingroup httpd - * Structure defining the base filename (URL) of a CGI and the associated - * function which is to be called when that URL is requested. - */ -typedef struct -{ - const char *pcCGIName; - tCGIHandler pfnCGIHandler; -} tCGI; - -void http_set_cgi_handlers(const tCGI *pCGIs, int iNumHandlers); - -#endif /* LWIP_HTTPD_CGI */ - -#if LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI - -#if LWIP_HTTPD_CGI_SSI -/* we have to prototype this struct here to make it available for the handler */ -struct fs_file; - -/** Define this generic CGI handler in your application. - * It is called once for every URI with parameters. - * The parameters can be stored to the object passed as connection_state, which - * is allocated to file->state via fs_state_init() from fs_open() or fs_open_custom(). - * Content creation via SSI or complete dynamic files can retrieve the CGI params from there. - */ -extern void httpd_cgi_handler(struct fs_file *file, const char* uri, int iNumParams, - char **pcParam, char **pcValue -#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE - , void *connection_state -#endif /* LWIP_HTTPD_FILE_STATE */ - ); -#endif /* LWIP_HTTPD_CGI_SSI */ - -#endif /* LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI */ - -#if LWIP_HTTPD_SSI - -/** - * @ingroup httpd - * Function pointer for the SSI tag handler callback. - * - * This function will be called each time the HTTPD server detects a tag of the - * form in files with extensions mentioned in the g_pcSSIExtensions - * array (currently .shtml, .shtm, .ssi, .xml, .json) where "name" appears as - * one of the tags supplied to http_set_ssi_handler in the tags array. The - * returned insert string, which will be appended after the the string - * "" in file sent back to the client, should be written to pointer - * pcInsert. iInsertLen contains the size of the buffer pointed to by - * pcInsert. The iIndex parameter provides the zero-based index of the tag as - * found in the tags array and identifies the tag that is to be processed. - * - * The handler returns the number of characters written to pcInsert excluding - * any terminating NULL or HTTPD_SSI_TAG_UNKNOWN when tag is not recognized. - * - * Note that the behavior of this SSI mechanism is somewhat different from the - * "normal" SSI processing as found in, for example, the Apache web server. In - * this case, the inserted text is appended following the SSI tag rather than - * replacing the tag entirely. This allows for an implementation that does not - * require significant additional buffering of output data yet which will still - * offer usable SSI functionality. One downside to this approach is when - * attempting to use SSI within JavaScript. The SSI tag is structured to - * resemble an HTML comment but this syntax does not constitute a comment - * within JavaScript and, hence, leaving the tag in place will result in - * problems in these cases. In order to avoid these problems, define - * LWIP_HTTPD_SSI_INCLUDE_TAG as zero in your lwip options file, or use JavaScript - * style block comments in the form / * # name * / (without the spaces). - */ -typedef u16_t (*tSSIHandler)( -#if LWIP_HTTPD_SSI_RAW - const char* ssi_tag_name, -#else /* LWIP_HTTPD_SSI_RAW */ - int iIndex, -#endif /* LWIP_HTTPD_SSI_RAW */ - char *pcInsert, int iInsertLen -#if LWIP_HTTPD_SSI_MULTIPART - , u16_t current_tag_part, u16_t *next_tag_part -#endif /* LWIP_HTTPD_SSI_MULTIPART */ -#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE - , void *connection_state -#endif /* LWIP_HTTPD_FILE_STATE */ - ); - -/** Set the SSI handler function - * (if LWIP_HTTPD_SSI_RAW==1, only the first argument is used) - */ -void http_set_ssi_handler(tSSIHandler pfnSSIHandler, - const char **ppcTags, int iNumTags); - -/** For LWIP_HTTPD_SSI_RAW==1, return this to indicate the tag is unknown. - * In this case, the webserver writes a warning into the page. - * You can also just return 0 to write nothing for unknown tags. - */ -#define HTTPD_SSI_TAG_UNKNOWN 0xFFFF - -#endif /* LWIP_HTTPD_SSI */ - -#if LWIP_HTTPD_SUPPORT_POST - -/* These functions must be implemented by the application */ - -/** - * @ingroup httpd - * Called when a POST request has been received. The application can decide - * whether to accept it or not. - * - * @param connection Unique connection identifier, valid until httpd_post_end - * is called. - * @param uri The HTTP header URI receiving the POST request. - * @param http_request The raw HTTP request (the first packet, normally). - * @param http_request_len Size of 'http_request'. - * @param content_len Content-Length from HTTP header. - * @param response_uri Filename of response file, to be filled when denying the - * request - * @param response_uri_len Size of the 'response_uri' buffer. - * @param post_auto_wnd Set this to 0 to let the callback code handle window - * updates by calling 'httpd_post_data_recved' (to throttle rx speed) - * default is 1 (httpd handles window updates automatically) - * @return ERR_OK: Accept the POST request, data may be passed in - * another err_t: Deny the POST request, send back 'bad request'. - */ -err_t httpd_post_begin(void *connection, const char *uri, const char *http_request, - u16_t http_request_len, int content_len, char *response_uri, - u16_t response_uri_len, u8_t *post_auto_wnd); - -/** - * @ingroup httpd - * Called for each pbuf of data that has been received for a POST. - * ATTENTION: The application is responsible for freeing the pbufs passed in! - * - * @param connection Unique connection identifier. - * @param p Received data. - * @return ERR_OK: Data accepted. - * another err_t: Data denied, http_post_get_response_uri will be called. - */ -err_t httpd_post_receive_data(void *connection, struct pbuf *p); - -/** - * @ingroup httpd - * Called when all data is received or when the connection is closed. - * The application must return the filename/URI of a file to send in response - * to this POST request. If the response_uri buffer is untouched, a 404 - * response is returned. - * - * @param connection Unique connection identifier. - * @param response_uri Filename of response file, to be filled when denying the request - * @param response_uri_len Size of the 'response_uri' buffer. - */ -void httpd_post_finished(void *connection, char *response_uri, u16_t response_uri_len); - -#if LWIP_HTTPD_POST_MANUAL_WND -void httpd_post_data_recved(void *connection, u16_t recved_len); -#endif /* LWIP_HTTPD_POST_MANUAL_WND */ - -#endif /* LWIP_HTTPD_SUPPORT_POST */ - -void httpd_init(void); - -#if HTTPD_ENABLE_HTTPS -struct altcp_tls_config; -void httpd_inits(struct altcp_tls_config *conf); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_HTTPD_H */ diff --git a/core/c/include/lwip/apps/httpd_opts.h b/core/c/include/lwip/apps/httpd_opts.h deleted file mode 100755 index 733e117..0000000 --- a/core/c/include/lwip/apps/httpd_opts.h +++ /dev/null @@ -1,396 +0,0 @@ -/** - * @file - * HTTP server options list - */ - -/* - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - * This version of the file has been modified by Texas Instruments to offer - * simple server-side-include (SSI) and Common Gateway Interface (CGI) - * capability. - */ - -#ifndef LWIP_HDR_APPS_HTTPD_OPTS_H -#define LWIP_HDR_APPS_HTTPD_OPTS_H - -#include "lwip/opt.h" -#include "lwip/prot/iana.h" - -/** - * @defgroup httpd_opts Options - * @ingroup httpd - * @{ - */ - -/** Set this to 1 to support CGI (old style). - * - * This old style CGI support works by registering an array of URLs and - * associated CGI handler functions (@ref http_set_cgi_handlers). - * This list is scanned just before fs_open is called from request handling. - * The handler can return a new URL that is used internally by the httpd to - * load the returned page (passed to fs_open). - * - * Use this CGI type e.g. to execute specific actions and return a page that - * does not depend on the CGI parameters. - */ -#if !defined LWIP_HTTPD_CGI || defined __DOXYGEN__ -#define LWIP_HTTPD_CGI 0 -#endif - -/** Set this to 1 to support CGI (new style). - * - * This new style CGI support works by calling a global function - * (@ref tCGIHandler) for all URLs that are found. fs_open is called first - * and the URL can not be written by the CGI handler. Instead, this handler gets - * passed the http file state, an object where it can store information derived - * from the CGI URL or parameters. This file state is later passed to SSI, so - * the SSI code can return data depending on CGI input. - * - * Use this CGI handler if you want CGI information passed on to SSI. - */ -#if !defined LWIP_HTTPD_CGI_SSI || defined __DOXYGEN__ -#define LWIP_HTTPD_CGI_SSI 0 -#endif - -/** Set this to 1 to support SSI (Server-Side-Includes) - * - * In contrast to other http servers, this only calls a preregistered callback - * function (@see http_set_ssi_handler) for each tag (in the format of - * ) encountered in SSI-enabled pages. - * SSI-enabled pages must have one of the predefined SSI-enabled file extensions. - * All files with one of these extensions are parsed when sent. - * - * A downside of the current SSI implementation is that persistent connections - * don't work, as the file length is not known in advance (and httpd currently - * relies on the Content-Length header for persistent connections). - * - * To save memory, the maximum tag length is limited (@see LWIP_HTTPD_MAX_TAG_NAME_LEN). - * To save memory, the maximum insertion string length is limited (@see - * LWIP_HTTPD_MAX_TAG_INSERT_LEN). If this is not enought, @ref LWIP_HTTPD_SSI_MULTIPART - * can be used. - */ -#if !defined LWIP_HTTPD_SSI || defined __DOXYGEN__ -#define LWIP_HTTPD_SSI 0 -#endif - -/** Set this to 1 to implement an SSI tag handler callback that gets a const char* - * to the tag (instead of an index into a pre-registered array of known tags) - * If this is 0, the SSI handler callback function is only called pre-registered tags. - */ -#if !defined LWIP_HTTPD_SSI_RAW || defined __DOXYGEN__ -#define LWIP_HTTPD_SSI_RAW 0 -#endif - -/** Set this to 0 to prevent parsing the file extension at runtime to decide - * if a file should be scanned for SSI tags or not. - * Default is 1 (file extensions are checked using the g_pcSSIExtensions array) - * Set to 2 to override this runtime test function. - * - * This is enabled by default, but if you only use a newer version of makefsdata - * supporting the "-ssi" option, this info is already present in - */ -#if !defined LWIP_HTTPD_SSI_BY_FILE_EXTENSION || defined __DOXYGEN__ -#define LWIP_HTTPD_SSI_BY_FILE_EXTENSION 1 -#endif - -/** Set this to 1 to support HTTP POST */ -#if !defined LWIP_HTTPD_SUPPORT_POST || defined __DOXYGEN__ -#define LWIP_HTTPD_SUPPORT_POST 0 -#endif - -/* The maximum number of parameters that the CGI handler can be sent. */ -#if !defined LWIP_HTTPD_MAX_CGI_PARAMETERS || defined __DOXYGEN__ -#define LWIP_HTTPD_MAX_CGI_PARAMETERS 16 -#endif - -/** LWIP_HTTPD_SSI_MULTIPART==1: SSI handler function is called with 2 more - * arguments indicating a counter for insert string that are too long to be - * inserted at once: the SSI handler function must then set 'next_tag_part' - * which will be passed back to it in the next call. */ -#if !defined LWIP_HTTPD_SSI_MULTIPART || defined __DOXYGEN__ -#define LWIP_HTTPD_SSI_MULTIPART 0 -#endif - -/* The maximum length of the string comprising the SSI tag name - * ATTENTION: tags longer than this are ignored, not truncated! - */ -#if !defined LWIP_HTTPD_MAX_TAG_NAME_LEN || defined __DOXYGEN__ -#define LWIP_HTTPD_MAX_TAG_NAME_LEN 8 -#endif - -/* The maximum length of string that can be returned to replace any given tag - * If this buffer is not long enough, use LWIP_HTTPD_SSI_MULTIPART. - */ -#if !defined LWIP_HTTPD_MAX_TAG_INSERT_LEN || defined __DOXYGEN__ -#define LWIP_HTTPD_MAX_TAG_INSERT_LEN 192 -#endif - -#if !defined LWIP_HTTPD_POST_MANUAL_WND || defined __DOXYGEN__ -#define LWIP_HTTPD_POST_MANUAL_WND 0 -#endif - -/** This string is passed in the HTTP header as "Server: " */ -#if !defined HTTPD_SERVER_AGENT || defined __DOXYGEN__ -#define HTTPD_SERVER_AGENT "lwIP/" LWIP_VERSION_STRING " (http://savannah.nongnu.org/projects/lwip)" -#endif - -/** Set this to 1 if you want to include code that creates HTTP headers - * at runtime. Default is off: HTTP headers are then created statically - * by the makefsdata tool. Static headers mean smaller code size, but - * the (readonly) fsdata will grow a bit as every file includes the HTTP - * header. */ -#if !defined LWIP_HTTPD_DYNAMIC_HEADERS || defined __DOXYGEN__ -#define LWIP_HTTPD_DYNAMIC_HEADERS 0 -#endif - -#if !defined HTTPD_DEBUG || defined __DOXYGEN__ -#define HTTPD_DEBUG LWIP_DBG_OFF -#endif - -/** Set this to 1 to use a memp pool for allocating - * struct http_state instead of the heap. - * If enabled, you'll need to define MEMP_NUM_PARALLEL_HTTPD_CONNS - * (and MEMP_NUM_PARALLEL_HTTPD_SSI_CONNS for SSI) to set the size of - * the pool(s). - */ -#if !defined HTTPD_USE_MEM_POOL || defined __DOXYGEN__ -#define HTTPD_USE_MEM_POOL 0 -#endif - -/** The server port for HTTPD to use */ -#if !defined HTTPD_SERVER_PORT || defined __DOXYGEN__ -#define HTTPD_SERVER_PORT LWIP_IANA_PORT_HTTP -#endif - -/** The https server port for HTTPD to use */ -#if !defined HTTPD_SERVER_PORT_HTTPS || defined __DOXYGEN__ -#define HTTPD_SERVER_PORT_HTTPS LWIP_IANA_PORT_HTTPS -#endif - -/** Enable https support? */ -#if !defined HTTPD_ENABLE_HTTPS || defined __DOXYGEN__ -#define HTTPD_ENABLE_HTTPS 0 -#endif - -/** Maximum retries before the connection is aborted/closed. - * - number of times pcb->poll is called -> default is 4*500ms = 2s; - * - reset when pcb->sent is called - */ -#if !defined HTTPD_MAX_RETRIES || defined __DOXYGEN__ -#define HTTPD_MAX_RETRIES 4 -#endif - -/** The poll delay is X*500ms */ -#if !defined HTTPD_POLL_INTERVAL || defined __DOXYGEN__ -#define HTTPD_POLL_INTERVAL 4 -#endif - -/** Priority for tcp pcbs created by HTTPD (very low by default). - * Lower priorities get killed first when running out of memory. - */ -#if !defined HTTPD_TCP_PRIO || defined __DOXYGEN__ -#define HTTPD_TCP_PRIO TCP_PRIO_MIN -#endif - -/** Set this to 1 to enable timing each file sent */ -#if !defined LWIP_HTTPD_TIMING || defined __DOXYGEN__ -#define LWIP_HTTPD_TIMING 0 -#endif -/** Set this to 1 to enable timing each file sent */ -#if !defined HTTPD_DEBUG_TIMING || defined __DOXYGEN__ -#define HTTPD_DEBUG_TIMING LWIP_DBG_OFF -#endif - -/** Set this to one to show error pages when parsing a request fails instead - of simply closing the connection. */ -#if !defined LWIP_HTTPD_SUPPORT_EXTSTATUS || defined __DOXYGEN__ -#define LWIP_HTTPD_SUPPORT_EXTSTATUS 0 -#endif - -/** Set this to 0 to drop support for HTTP/0.9 clients (to save some bytes) */ -#if !defined LWIP_HTTPD_SUPPORT_V09 || defined __DOXYGEN__ -#define LWIP_HTTPD_SUPPORT_V09 1 -#endif - -/** Set this to 1 to enable HTTP/1.1 persistent connections. - * ATTENTION: If the generated file system includes HTTP headers, these must - * include the "Connection: keep-alive" header (pass argument "-11" to makefsdata). - */ -#if !defined LWIP_HTTPD_SUPPORT_11_KEEPALIVE || defined __DOXYGEN__ -#define LWIP_HTTPD_SUPPORT_11_KEEPALIVE 0 -#endif - -/** Set this to 1 to support HTTP request coming in in multiple packets/pbufs */ -#if !defined LWIP_HTTPD_SUPPORT_REQUESTLIST || defined __DOXYGEN__ -#define LWIP_HTTPD_SUPPORT_REQUESTLIST 1 -#endif - -#if LWIP_HTTPD_SUPPORT_REQUESTLIST -/** Number of rx pbufs to enqueue to parse an incoming request (up to the first - newline) */ -#if !defined LWIP_HTTPD_REQ_QUEUELEN || defined __DOXYGEN__ -#define LWIP_HTTPD_REQ_QUEUELEN 5 -#endif - -/** Number of (TCP payload-) bytes (in pbufs) to enqueue to parse and incoming - request (up to the first double-newline) */ -#if !defined LWIP_HTTPD_REQ_BUFSIZE || defined __DOXYGEN__ -#define LWIP_HTTPD_REQ_BUFSIZE LWIP_HTTPD_MAX_REQ_LENGTH -#endif - -/** Defines the maximum length of a HTTP request line (up to the first CRLF, - copied from pbuf into this a global buffer when pbuf- or packet-queues - are received - otherwise the input pbuf is used directly) */ -#if !defined LWIP_HTTPD_MAX_REQ_LENGTH || defined __DOXYGEN__ -#define LWIP_HTTPD_MAX_REQ_LENGTH LWIP_MIN(1023, (LWIP_HTTPD_REQ_QUEUELEN * PBUF_POOL_BUFSIZE)) -#endif -#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ - -/** This is the size of a static buffer used when URIs end with '/'. - * In this buffer, the directory requested is concatenated with all the - * configured default file names. - * Set to 0 to disable checking default filenames on non-root directories. - */ -#if !defined LWIP_HTTPD_MAX_REQUEST_URI_LEN || defined __DOXYGEN__ -#define LWIP_HTTPD_MAX_REQUEST_URI_LEN 63 -#endif - -/** Maximum length of the filename to send as response to a POST request, - * filled in by the application when a POST is finished. - */ -#if !defined LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN || defined __DOXYGEN__ -#define LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN 63 -#endif - -/** Set this to 0 to not send the SSI tag (default is on, so the tag will - * be sent in the HTML page */ -#if !defined LWIP_HTTPD_SSI_INCLUDE_TAG || defined __DOXYGEN__ -#define LWIP_HTTPD_SSI_INCLUDE_TAG 1 -#endif - -/** Set this to 1 to call tcp_abort when tcp_close fails with memory error. - * This can be used to prevent consuming all memory in situations where the - * HTTP server has low priority compared to other communication. */ -#if !defined LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR || defined __DOXYGEN__ -#define LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR 0 -#endif - -/** Set this to 1 to kill the oldest connection when running out of - * memory for 'struct http_state' or 'struct http_ssi_state'. - * ATTENTION: This puts all connections on a linked list, so may be kind of slow. - */ -#if !defined LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED || defined __DOXYGEN__ -#define LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED 0 -#endif - -/** Set this to 1 to send URIs without extension without headers - * (who uses this at all??) */ -#if !defined LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI || defined __DOXYGEN__ -#define LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI 0 -#endif - -/** Default: Tags are sent from struct http_state and are therefore volatile */ -#if !defined HTTP_IS_TAG_VOLATILE || defined __DOXYGEN__ -#define HTTP_IS_TAG_VOLATILE(ptr) TCP_WRITE_FLAG_COPY -#endif - -/* By default, the httpd is limited to send 2*pcb->mss to keep resource usage low - when http is not an important protocol in the device. */ -#if !defined HTTPD_LIMIT_SENDING_TO_2MSS || defined __DOXYGEN__ -#define HTTPD_LIMIT_SENDING_TO_2MSS 1 -#endif - -/* Define this to a function that returns the maximum amount of data to enqueue. - The function have this signature: u16_t fn(struct altcp_pcb* pcb); - The best place to define this is the hooks file (@see LWIP_HOOK_FILENAME) */ -#if !defined HTTPD_MAX_WRITE_LEN || defined __DOXYGEN__ -#if HTTPD_LIMIT_SENDING_TO_2MSS -#define HTTPD_MAX_WRITE_LEN(pcb) ((u16_t)(2 * altcp_mss(pcb))) -#endif -#endif - -/*------------------- FS OPTIONS -------------------*/ - -/** Set this to 1 and provide the functions: - * - "int fs_open_custom(struct fs_file *file, const char *name)" - * Called first for every opened file to allow opening files - * that are not included in fsdata(_custom).c - * - "void fs_close_custom(struct fs_file *file)" - * Called to free resources allocated by fs_open_custom(). - */ -#if !defined LWIP_HTTPD_CUSTOM_FILES || defined __DOXYGEN__ -#define LWIP_HTTPD_CUSTOM_FILES 0 -#endif - -/** Set this to 1 to support fs_read() to dynamically read file data. - * Without this (default=off), only one-block files are supported, - * and the contents must be ready after fs_open(). - */ -#if !defined LWIP_HTTPD_DYNAMIC_FILE_READ || defined __DOXYGEN__ -#define LWIP_HTTPD_DYNAMIC_FILE_READ 0 -#endif - -/** Set this to 1 to include an application state argument per file - * that is opened. This allows to keep a state per connection/file. - */ -#if !defined LWIP_HTTPD_FILE_STATE || defined __DOXYGEN__ -#define LWIP_HTTPD_FILE_STATE 0 -#endif - -/** HTTPD_PRECALCULATED_CHECKSUM==1: include precompiled checksums for - * predefined (MSS-sized) chunks of the files to prevent having to calculate - * the checksums at runtime. */ -#if !defined HTTPD_PRECALCULATED_CHECKSUM || defined __DOXYGEN__ -#define HTTPD_PRECALCULATED_CHECKSUM 0 -#endif - -/** LWIP_HTTPD_FS_ASYNC_READ==1: support asynchronous read operations - * (fs_read_async returns FS_READ_DELAYED and calls a callback when finished). - */ -#if !defined LWIP_HTTPD_FS_ASYNC_READ || defined __DOXYGEN__ -#define LWIP_HTTPD_FS_ASYNC_READ 0 -#endif - -/** Filename (including path) to use as FS data file */ -#if !defined HTTPD_FSDATA_FILE || defined __DOXYGEN__ -/* HTTPD_USE_CUSTOM_FSDATA: Compatibility with deprecated lwIP option */ -#if defined(HTTPD_USE_CUSTOM_FSDATA) && (HTTPD_USE_CUSTOM_FSDATA != 0) -#define HTTPD_FSDATA_FILE "fsdata_custom.c" -#else -#define HTTPD_FSDATA_FILE "fsdata.c" -#endif -#endif - -/** - * @} - */ - -#endif /* LWIP_HDR_APPS_HTTPD_OPTS_H */ diff --git a/core/c/include/lwip/apps/lwiperf.h b/core/c/include/lwip/apps/lwiperf.h deleted file mode 100755 index ff4d6f7..0000000 --- a/core/c/include/lwip/apps/lwiperf.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @file - * lwIP iPerf server implementation - */ - -/* - * Copyright (c) 2014 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ -#ifndef LWIP_HDR_APPS_LWIPERF_H -#define LWIP_HDR_APPS_LWIPERF_H - -#include "lwip/opt.h" -#include "lwip/ip_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define LWIPERF_TCP_PORT_DEFAULT 5001 - -/** lwIPerf test results */ -enum lwiperf_report_type -{ - /** The server side test is done */ - LWIPERF_TCP_DONE_SERVER, - /** The client side test is done */ - LWIPERF_TCP_DONE_CLIENT, - /** Local error lead to test abort */ - LWIPERF_TCP_ABORTED_LOCAL, - /** Data check error lead to test abort */ - LWIPERF_TCP_ABORTED_LOCAL_DATAERROR, - /** Transmit error lead to test abort */ - LWIPERF_TCP_ABORTED_LOCAL_TXERROR, - /** Remote side aborted the test */ - LWIPERF_TCP_ABORTED_REMOTE -}; - -/** Control */ -enum lwiperf_client_type -{ - /** Unidirectional tx only test */ - LWIPERF_CLIENT, - /** Do a bidirectional test simultaneously */ - LWIPERF_DUAL, - /** Do a bidirectional test individually */ - LWIPERF_TRADEOFF -}; - -/** Prototype of a report function that is called when a session is finished. - This report function can show the test results. - @param report_type contains the test result */ -typedef void (*lwiperf_report_fn)(void *arg, enum lwiperf_report_type report_type, - const ip_addr_t* local_addr, u16_t local_port, const ip_addr_t* remote_addr, u16_t remote_port, - u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec); - -void* lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port, - lwiperf_report_fn report_fn, void* report_arg); -void* lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg); -void* lwiperf_start_tcp_client(const ip_addr_t* remote_addr, u16_t remote_port, - enum lwiperf_client_type type, - lwiperf_report_fn report_fn, void* report_arg); -void* lwiperf_start_tcp_client_default(const ip_addr_t* remote_addr, - lwiperf_report_fn report_fn, void* report_arg); - -void lwiperf_abort(void* lwiperf_session); - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_LWIPERF_H */ diff --git a/core/c/include/lwip/apps/mdns.h b/core/c/include/lwip/apps/mdns.h deleted file mode 100755 index 3c3d054..0000000 --- a/core/c/include/lwip/apps/mdns.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @file - * MDNS responder - */ - - /* - * Copyright (c) 2015 Verisure Innovation AB - * 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: Erik Ekman - * - */ - -#ifndef LWIP_HDR_APPS_MDNS_H -#define LWIP_HDR_APPS_MDNS_H - -#include "lwip/apps/mdns_opts.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_MDNS_RESPONDER - -enum mdns_sd_proto { - DNSSD_PROTO_UDP = 0, - DNSSD_PROTO_TCP = 1 -}; - -#define MDNS_PROBING_CONFLICT 0 -#define MDNS_PROBING_SUCCESSFUL 1 - -#define MDNS_LABEL_MAXLEN 63 - -struct mdns_host; -struct mdns_service; - -/** Callback function to add text to a reply, called when generating the reply */ -typedef void (*service_get_txt_fn_t)(struct mdns_service *service, void *txt_userdata); - -/** Callback function to let application know the result of probing network for name - * uniqueness, called with result MDNS_PROBING_SUCCESSFUL if no other node claimed - * use for the name for the netif or a service and is safe to use, or MDNS_PROBING_CONFLICT - * if another node is already using it and mdns is disabled on this interface */ -typedef void (*mdns_name_result_cb_t)(struct netif* netif, u8_t result); - -void mdns_resp_init(void); - -void mdns_resp_register_name_result_cb(mdns_name_result_cb_t cb); - -err_t mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl); -err_t mdns_resp_remove_netif(struct netif *netif); -err_t mdns_resp_rename_netif(struct netif *netif, const char *hostname); - -s8_t mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_userdata); -err_t mdns_resp_del_service(struct netif *netif, s8_t slot); -err_t mdns_resp_rename_service(struct netif *netif, s8_t slot, const char *name); - -err_t mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_t txt_len); - -void mdns_resp_restart(struct netif *netif); -void mdns_resp_announce(struct netif *netif); - -/** - * @ingroup mdns - * Announce IP settings have changed on netif. - * Call this in your callback registered by netif_set_status_callback(). - * No need to call this function when LWIP_NETIF_EXT_STATUS_CALLBACK==1, - * this handled automatically for you. - * @param netif The network interface where settings have changed. - */ -#define mdns_resp_netif_settings_changed(netif) mdns_resp_announce(netif) - -#endif /* LWIP_MDNS_RESPONDER */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_MDNS_H */ diff --git a/core/c/include/lwip/apps/mdns_opts.h b/core/c/include/lwip/apps/mdns_opts.h deleted file mode 100755 index 74d3f41..0000000 --- a/core/c/include/lwip/apps/mdns_opts.h +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @file - * MDNS responder - */ - - /* - * Copyright (c) 2015 Verisure Innovation AB - * 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: Erik Ekman - * - */ - -#ifndef LWIP_HDR_APPS_MDNS_OPTS_H -#define LWIP_HDR_APPS_MDNS_OPTS_H - -#include "lwip/opt.h" - -/** - * @defgroup mdns_opts Options - * @ingroup mdns - * @{ - */ - -/** - * LWIP_MDNS_RESPONDER==1: Turn on multicast DNS module. UDP must be available for MDNS - * transport. IGMP is needed for IPv4 multicast. - */ -#ifndef LWIP_MDNS_RESPONDER -#define LWIP_MDNS_RESPONDER 0 -#endif /* LWIP_MDNS_RESPONDER */ - -/** The maximum number of services per netif */ -#ifndef MDNS_MAX_SERVICES -#define MDNS_MAX_SERVICES 1 -#endif - -/** MDNS_RESP_USENETIF_EXTCALLBACK==1: register an ext_callback on the netif - * to automatically restart probing/announcing on status or address change. - */ -#ifndef MDNS_RESP_USENETIF_EXTCALLBACK -#define MDNS_RESP_USENETIF_EXTCALLBACK LWIP_NETIF_EXT_STATUS_CALLBACK -#endif - -/** - * MDNS_DEBUG: Enable debugging for multicast DNS. - */ -#ifndef MDNS_DEBUG -#define MDNS_DEBUG LWIP_DBG_OFF -#endif - -/** - * @} - */ - -#endif /* LWIP_HDR_APPS_MDNS_OPTS_H */ - diff --git a/core/c/include/lwip/apps/mdns_priv.h b/core/c/include/lwip/apps/mdns_priv.h deleted file mode 100755 index 2394157..0000000 --- a/core/c/include/lwip/apps/mdns_priv.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file - * MDNS responder private definitions - */ - - /* - * Copyright (c) 2015 Verisure Innovation AB - * 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: Erik Ekman - * - */ -#ifndef LWIP_HDR_MDNS_PRIV_H -#define LWIP_HDR_MDNS_PRIV_H - -#include "lwip/apps/mdns_opts.h" -#include "lwip/pbuf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_MDNS_RESPONDER - -/* Domain struct and methods - visible for unit tests */ - -#define MDNS_DOMAIN_MAXLEN 256 -#define MDNS_READNAME_ERROR 0xFFFF - -struct mdns_domain { - /* Encoded domain name */ - u8_t name[MDNS_DOMAIN_MAXLEN]; - /* Total length of domain name, including zero */ - u16_t length; - /* Set if compression of this domain is not allowed */ - u8_t skip_compression; -}; - -err_t mdns_domain_add_label(struct mdns_domain *domain, const char *label, u8_t len); -u16_t mdns_readname(struct pbuf *p, u16_t offset, struct mdns_domain *domain); -int mdns_domain_eq(struct mdns_domain *a, struct mdns_domain *b); -u16_t mdns_compress_domain(struct pbuf *pbuf, u16_t *offset, struct mdns_domain *domain); - -#endif /* LWIP_MDNS_RESPONDER */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_MDNS_PRIV_H */ diff --git a/core/c/include/lwip/apps/mqtt.h b/core/c/include/lwip/apps/mqtt.h deleted file mode 100755 index e796ae1..0000000 --- a/core/c/include/lwip/apps/mqtt.h +++ /dev/null @@ -1,205 +0,0 @@ -/** - * @file - * MQTT client - */ - -/* - * Copyright (c) 2016 Erik Andersson - * 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: Erik Andersson - * - */ -#ifndef LWIP_HDR_APPS_MQTT_CLIENT_H -#define LWIP_HDR_APPS_MQTT_CLIENT_H - -#include "lwip/apps/mqtt_opts.h" -#include "lwip/err.h" -#include "lwip/ip_addr.h" -#include "lwip/prot/iana.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct mqtt_client_s mqtt_client_t; - -#if LWIP_ALTCP && LWIP_ALTCP_TLS -struct altcp_tls_config; -#endif - -/** @ingroup mqtt - * Default MQTT port (non-TLS) */ -#define MQTT_PORT LWIP_IANA_PORT_MQTT -/** @ingroup mqtt - * Default MQTT TLS port */ -#define MQTT_TLS_PORT LWIP_IANA_PORT_SECURE_MQTT - -/*---------------------------------------------------------------------------------------------- */ -/* Connection with server */ - -/** - * @ingroup mqtt - * Client information and connection parameters */ -struct mqtt_connect_client_info_t { - /** Client identifier, must be set by caller */ - const char *client_id; - /** User name, set to NULL if not used */ - const char* client_user; - /** Password, set to NULL if not used */ - const char* client_pass; - /** keep alive time in seconds, 0 to disable keep alive functionality*/ - u16_t keep_alive; - /** will topic, set to NULL if will is not to be used, - will_msg, will_qos and will retain are then ignored */ - const char* will_topic; - /** will_msg, see will_topic */ - const char* will_msg; - /** will_qos, see will_topic */ - u8_t will_qos; - /** will_retain, see will_topic */ - u8_t will_retain; -#if LWIP_ALTCP && LWIP_ALTCP_TLS - /** TLS configuration for secure connections */ - struct altcp_tls_config *tls_config; -#endif -}; - -/** - * @ingroup mqtt - * Connection status codes */ -typedef enum -{ - /** Accepted */ - MQTT_CONNECT_ACCEPTED = 0, - /** Refused protocol version */ - MQTT_CONNECT_REFUSED_PROTOCOL_VERSION = 1, - /** Refused identifier */ - MQTT_CONNECT_REFUSED_IDENTIFIER = 2, - /** Refused server */ - MQTT_CONNECT_REFUSED_SERVER = 3, - /** Refused user credentials */ - MQTT_CONNECT_REFUSED_USERNAME_PASS = 4, - /** Refused not authorized */ - MQTT_CONNECT_REFUSED_NOT_AUTHORIZED_ = 5, - /** Disconnected */ - MQTT_CONNECT_DISCONNECTED = 256, - /** Timeout */ - MQTT_CONNECT_TIMEOUT = 257 -} mqtt_connection_status_t; - -/** - * @ingroup mqtt - * Function prototype for mqtt connection status callback. Called when - * client has connected to the server after initiating a mqtt connection attempt by - * calling mqtt_client_connect() or when connection is closed by server or an error - * - * @param client MQTT client itself - * @param arg Additional argument to pass to the callback function - * @param status Connect result code or disconnection notification @see mqtt_connection_status_t - * - */ -typedef void (*mqtt_connection_cb_t)(mqtt_client_t *client, void *arg, mqtt_connection_status_t status); - - -/** - * @ingroup mqtt - * Data callback flags */ -enum { - /** Flag set when last fragment of data arrives in data callback */ - MQTT_DATA_FLAG_LAST = 1 -}; - -/** - * @ingroup mqtt - * Function prototype for MQTT incoming publish data callback function. Called when data - * arrives to a subscribed topic @see mqtt_subscribe - * - * @param arg Additional argument to pass to the callback function - * @param data User data, pointed object, data may not be referenced after callback return, - NULL is passed when all publish data are delivered - * @param len Length of publish data fragment - * @param flags MQTT_DATA_FLAG_LAST set when this call contains the last part of data from publish message - * - */ -typedef void (*mqtt_incoming_data_cb_t)(void *arg, const u8_t *data, u16_t len, u8_t flags); - - -/** - * @ingroup mqtt - * Function prototype for MQTT incoming publish function. Called when an incoming publish - * arrives to a subscribed topic @see mqtt_subscribe - * - * @param arg Additional argument to pass to the callback function - * @param topic Zero terminated Topic text string, topic may not be referenced after callback return - * @param tot_len Total length of publish data, if set to 0 (no publish payload) data callback will not be invoked - */ -typedef void (*mqtt_incoming_publish_cb_t)(void *arg, const char *topic, u32_t tot_len); - - -/** - * @ingroup mqtt - * Function prototype for mqtt request callback. Called when a subscribe, unsubscribe - * or publish request has completed - * @param arg Pointer to user data supplied when invoking request - * @param err ERR_OK on success - * ERR_TIMEOUT if no response was received within timeout, - * ERR_ABRT if (un)subscribe was denied - */ -typedef void (*mqtt_request_cb_t)(void *arg, err_t err); - - -err_t mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ipaddr, u16_t port, mqtt_connection_cb_t cb, void *arg, - const struct mqtt_connect_client_info_t *client_info); - -void mqtt_disconnect(mqtt_client_t *client); - -mqtt_client_t *mqtt_client_new(void); -void mqtt_client_free(mqtt_client_t* client); - -u8_t mqtt_client_is_connected(mqtt_client_t *client); - -void mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t, - mqtt_incoming_data_cb_t data_cb, void *arg); - -err_t mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_cb_t cb, void *arg, u8_t sub); - -/** @ingroup mqtt - *Subscribe to topic */ -#define mqtt_subscribe(client, topic, qos, cb, arg) mqtt_sub_unsub(client, topic, qos, cb, arg, 1) -/** @ingroup mqtt - * Unsubscribe to topic */ -#define mqtt_unsubscribe(client, topic, cb, arg) mqtt_sub_unsub(client, topic, 0, cb, arg, 0) - -err_t mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_t payload_length, u8_t qos, u8_t retain, - mqtt_request_cb_t cb, void *arg); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_MQTT_CLIENT_H */ diff --git a/core/c/include/lwip/apps/mqtt_opts.h b/core/c/include/lwip/apps/mqtt_opts.h deleted file mode 100755 index e056130..0000000 --- a/core/c/include/lwip/apps/mqtt_opts.h +++ /dev/null @@ -1,103 +0,0 @@ -/** - * @file - * MQTT client options - */ - -/* - * Copyright (c) 2016 Erik Andersson - * 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: Erik Andersson - * - */ -#ifndef LWIP_HDR_APPS_MQTT_OPTS_H -#define LWIP_HDR_APPS_MQTT_OPTS_H - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup mqtt_opts Options - * @ingroup mqtt - * @{ - */ - -/** - * Output ring-buffer size, must be able to fit largest outgoing publish message topic+payloads - */ -#ifndef MQTT_OUTPUT_RINGBUF_SIZE -#define MQTT_OUTPUT_RINGBUF_SIZE 256 -#endif - -/** - * Number of bytes in receive buffer, must be at least the size of the longest incoming topic + 8 - * If one wants to avoid fragmented incoming publish, set length to max incoming topic length + max payload length + 8 - */ -#ifndef MQTT_VAR_HEADER_BUFFER_LEN -#define MQTT_VAR_HEADER_BUFFER_LEN 128 -#endif - -/** - * Maximum number of pending subscribe, unsubscribe and publish requests to server . - */ -#ifndef MQTT_REQ_MAX_IN_FLIGHT -#define MQTT_REQ_MAX_IN_FLIGHT 4 -#endif - -/** - * Seconds between each cyclic timer call. - */ -#ifndef MQTT_CYCLIC_TIMER_INTERVAL -#define MQTT_CYCLIC_TIMER_INTERVAL 5 -#endif - -/** - * Publish, subscribe and unsubscribe request timeout in seconds. - */ -#ifndef MQTT_REQ_TIMEOUT -#define MQTT_REQ_TIMEOUT 30 -#endif - -/** - * Seconds for MQTT connect response timeout after sending connect request - */ -#ifndef MQTT_CONNECT_TIMOUT -#define MQTT_CONNECT_TIMOUT 100 -#endif - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_MQTT_OPTS_H */ diff --git a/core/c/include/lwip/apps/mqtt_priv.h b/core/c/include/lwip/apps/mqtt_priv.h deleted file mode 100755 index 04d2336..0000000 --- a/core/c/include/lwip/apps/mqtt_priv.h +++ /dev/null @@ -1,104 +0,0 @@ -/** - * @file - * MQTT client (private interface) - */ - -/* - * Copyright (c) 2016 Erik Andersson - * 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: Erik Andersson - * - */ -#ifndef LWIP_HDR_APPS_MQTT_PRIV_H -#define LWIP_HDR_APPS_MQTT_PRIV_H - -#include "lwip/apps/mqtt.h" -#include "lwip/altcp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Pending request item, binds application callback to pending server requests */ -struct mqtt_request_t -{ - /** Next item in list, NULL means this is the last in chain, - next pointing at itself means request is unallocated */ - struct mqtt_request_t *next; - /** Callback to upper layer */ - mqtt_request_cb_t cb; - void *arg; - /** MQTT packet identifier */ - u16_t pkt_id; - /** Expire time relative to element before this */ - u16_t timeout_diff; -}; - -/** Ring buffer */ -struct mqtt_ringbuf_t { - u16_t put; - u16_t get; - u8_t buf[MQTT_OUTPUT_RINGBUF_SIZE]; -}; - -/** MQTT client */ -struct mqtt_client_s -{ - /** Timers and timeouts */ - u16_t cyclic_tick; - u16_t keep_alive; - u16_t server_watchdog; - /** Packet identifier generator*/ - u16_t pkt_id_seq; - /** Packet identifier of pending incoming publish */ - u16_t inpub_pkt_id; - /** Connection state */ - u8_t conn_state; - struct altcp_pcb *conn; - /** Connection callback */ - void *connect_arg; - mqtt_connection_cb_t connect_cb; - /** Pending requests to server */ - struct mqtt_request_t *pend_req_queue; - struct mqtt_request_t req_list[MQTT_REQ_MAX_IN_FLIGHT]; - void *inpub_arg; - /** Incoming data callback */ - mqtt_incoming_data_cb_t data_cb; - mqtt_incoming_publish_cb_t pub_cb; - /** Input */ - u32_t msg_idx; - u8_t rx_buffer[MQTT_VAR_HEADER_BUFFER_LEN]; - /** Output ring-buffer */ - struct mqtt_ringbuf_t output; -}; - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_MQTT_PRIV_H */ diff --git a/core/c/include/lwip/apps/netbiosns.h b/core/c/include/lwip/apps/netbiosns.h deleted file mode 100755 index c5aedb6..0000000 --- a/core/c/include/lwip/apps/netbiosns.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @file - * NETBIOS name service responder - */ - -/* - * 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_HDR_APPS_NETBIOS_H -#define LWIP_HDR_APPS_NETBIOS_H - -#include "lwip/apps/netbiosns_opts.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void netbiosns_init(void); -#ifndef NETBIOS_LWIP_NAME -void netbiosns_set_name(const char* hostname); -#endif -void netbiosns_stop(void); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_NETBIOS_H */ diff --git a/core/c/include/lwip/apps/netbiosns_opts.h b/core/c/include/lwip/apps/netbiosns_opts.h deleted file mode 100755 index 0bab59e..0000000 --- a/core/c/include/lwip/apps/netbiosns_opts.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file - * NETBIOS name service responder options - */ - -/* - * 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_HDR_APPS_NETBIOS_OPTS_H -#define LWIP_HDR_APPS_NETBIOS_OPTS_H - -#include "lwip/opt.h" - -/** - * @defgroup netbiosns_opts Options - * @ingroup netbiosns - * @{ - */ - -/** NetBIOS name of lwip device - * This must be uppercase until NETBIOS_STRCMP() is defined to a string - * comparision function that is case insensitive. - * If you want to use the netif's hostname, use this (with LWIP_NETIF_HOSTNAME): - * (ip_current_netif() != NULL ? ip_current_netif()->hostname != NULL ? ip_current_netif()->hostname : "" : "") - * - * If this is not defined, netbiosns_set_name() can be called at runtime to change the name. - */ -#ifdef __DOXYGEN__ -#define NETBIOS_LWIP_NAME "NETBIOSLWIPDEV" -#endif - -/** Respond to NetBIOS name queries - * Default is disabled - */ -#if !defined LWIP_NETBIOS_RESPOND_NAME_QUERY || defined __DOXYGEN__ -#define LWIP_NETBIOS_RESPOND_NAME_QUERY 0 -#endif - -/** - * @} - */ - -#endif /* LWIP_HDR_APPS_NETBIOS_OPTS_H */ diff --git a/core/c/include/lwip/apps/smtp.h b/core/c/include/lwip/apps/smtp.h deleted file mode 100755 index e6076a1..0000000 --- a/core/c/include/lwip/apps/smtp.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef LWIP_HDR_APPS_SMTP_H -#define LWIP_HDR_APPS_SMTP_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "lwip/apps/smtp_opts.h" -#include "lwip/err.h" -#include "lwip/prot/iana.h" - -/** The default TCP port used for SMTP */ -#define SMTP_DEFAULT_PORT LWIP_IANA_PORT_SMTP -/** The default TCP port used for SMTPS */ -#define SMTPS_DEFAULT_PORT LWIP_IANA_PORT_SMTPS - -/** Email successfully sent */ -#define SMTP_RESULT_OK 0 -/** Unknown error */ -#define SMTP_RESULT_ERR_UNKNOWN 1 -/** Connection to server failed */ -#define SMTP_RESULT_ERR_CONNECT 2 -/** Failed to resolve server hostname */ -#define SMTP_RESULT_ERR_HOSTNAME 3 -/** Connection unexpectedly closed by remote server */ -#define SMTP_RESULT_ERR_CLOSED 4 -/** Connection timed out (server didn't respond in time) */ -#define SMTP_RESULT_ERR_TIMEOUT 5 -/** Server responded with an unknown response code */ -#define SMTP_RESULT_ERR_SVR_RESP 6 -/** Out of resources locally */ -#define SMTP_RESULT_ERR_MEM 7 - -/** Prototype of an smtp callback function - * - * @param arg argument specified when initiating the email - * @param smtp_result result of the mail transfer (see defines SMTP_RESULT_*) - * @param srv_err if aborted by the server, this contains the error code received - * @param err an error returned by internal lwip functions, can help to specify - * the source of the error but must not necessarily be != ERR_OK - */ -typedef void (*smtp_result_fn)(void *arg, u8_t smtp_result, u16_t srv_err, err_t err); - -/** This structure is used as argument for smtp_send_mail_int(), - * which in turn can be used with tcpip_callback() to send mail - * from interrupt context, e.g. like this: - * struct smtp_send_request *req; (to be filled) - * tcpip_try_callback(smtp_send_mail_int, (void*)req); - * - * For member description, see parameter description of smtp_send_mail(). - * When using with tcpip_callback, this structure has to stay allocated - * (e.g. using mem_malloc/mem_free) until its 'callback_fn' is called. - */ -struct smtp_send_request { - const char *from; - const char* to; - const char* subject; - const char* body; - smtp_result_fn callback_fn; - void* callback_arg; - /** If this is != 0, data is *not* copied into an extra buffer - * but used from the pointers supplied in this struct. - * This means less memory usage, but data must stay untouched until - * the callback function is called. */ - u8_t static_data; -}; - - -#if SMTP_BODYDH - -#ifndef SMTP_BODYDH_BUFFER_SIZE -#define SMTP_BODYDH_BUFFER_SIZE 256 -#endif /* SMTP_BODYDH_BUFFER_SIZE */ - -struct smtp_bodydh { - u16_t state; - u16_t length; /* Length of content in buffer */ - char buffer[SMTP_BODYDH_BUFFER_SIZE]; /* buffer for generated content */ -#ifdef SMTP_BODYDH_USER_SIZE - u8_t user[SMTP_BODYDH_USER_SIZE]; -#endif /* SMTP_BODYDH_USER_SIZE */ -}; - -enum bdh_retvals_e { - BDH_DONE = 0, - BDH_WORKING -}; - -/** Prototype of an smtp body callback function - * It receives a struct smtp_bodydh, and a buffer to write data, - * must return BDH_WORKING to be called again and BDH_DONE when - * it has finished processing. This one tries to fill one TCP buffer with - * data, your function will be repeatedly called until that happens; so if you - * know you'll be taking too long to serve your request, pause once in a while - * by writing length=0 to avoid hogging system resources - * - * @param arg argument specified when initiating the email - * @param smtp_bodydh state handling + buffer structure - */ -typedef int (*smtp_bodycback_fn)(void *arg, struct smtp_bodydh *bodydh); - -err_t smtp_send_mail_bodycback(const char *from, const char* to, const char* subject, - smtp_bodycback_fn bodycback_fn, smtp_result_fn callback_fn, void* callback_arg); - -#endif /* SMTP_BODYDH */ - - -err_t smtp_set_server_addr(const char* server); -void smtp_set_server_port(u16_t port); -#if LWIP_ALTCP && LWIP_ALTCP_TLS -struct altcp_tls_config; -void smtp_set_tls_config(struct altcp_tls_config *tls_config); -#endif -err_t smtp_set_auth(const char* username, const char* pass); -err_t smtp_send_mail(const char *from, const char* to, const char* subject, const char* body, - smtp_result_fn callback_fn, void* callback_arg); -err_t smtp_send_mail_static(const char *from, const char* to, const char* subject, const char* body, - smtp_result_fn callback_fn, void* callback_arg); -void smtp_send_mail_int(void *arg); -#ifdef LWIP_DEBUG -const char* smtp_result_str(u8_t smtp_result); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_SMTP_H */ diff --git a/core/c/include/lwip/apps/smtp_opts.h b/core/c/include/lwip/apps/smtp_opts.h deleted file mode 100755 index 29c0c08..0000000 --- a/core/c/include/lwip/apps/smtp_opts.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef LWIP_HDR_APPS_SMTP_OPTS_H -#define LWIP_HDR_APPS_SMTP_OPTS_H - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup smtp_opts Options - * @ingroup smtp - * - * @{ - */ - -/** Set this to 1 to enable data handler callback on BODY */ -#ifndef SMTP_BODYDH -#define SMTP_BODYDH 0 -#endif - -/** SMTP_DEBUG: Enable debugging for SNTP. */ -#ifndef SMTP_DEBUG -#define SMTP_DEBUG LWIP_DBG_OFF -#endif - -/** Maximum length reserved for server name including terminating 0 byte */ -#ifndef SMTP_MAX_SERVERNAME_LEN -#define SMTP_MAX_SERVERNAME_LEN 256 -#endif - -/** Maximum length reserved for username */ -#ifndef SMTP_MAX_USERNAME_LEN -#define SMTP_MAX_USERNAME_LEN 32 -#endif - -/** Maximum length reserved for password */ -#ifndef SMTP_MAX_PASS_LEN -#define SMTP_MAX_PASS_LEN 32 -#endif - -/** Set this to 0 if you know the authentication data will not change - * during the smtp session, which saves some heap space. */ -#ifndef SMTP_COPY_AUTHDATA -#define SMTP_COPY_AUTHDATA 1 -#endif - -/** Set this to 0 to save some code space if you know for sure that all data - * passed to this module conforms to the requirements in the SMTP RFC. - * WARNING: use this with care! - */ -#ifndef SMTP_CHECK_DATA -#define SMTP_CHECK_DATA 1 -#endif - -/** Set this to 1 to enable AUTH PLAIN support */ -#ifndef SMTP_SUPPORT_AUTH_PLAIN -#define SMTP_SUPPORT_AUTH_PLAIN 1 -#endif - -/** Set this to 1 to enable AUTH LOGIN support */ -#ifndef SMTP_SUPPORT_AUTH_LOGIN -#define SMTP_SUPPORT_AUTH_LOGIN 1 -#endif - -/* Memory allocation/deallocation can be overridden... */ -#ifndef SMTP_STATE_MALLOC -#define SMTP_STATE_MALLOC(size) mem_malloc(size) -#define SMTP_STATE_FREE(ptr) mem_free(ptr) -#endif - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* SMTP_OPTS_H */ - diff --git a/core/c/include/lwip/apps/snmp.h b/core/c/include/lwip/apps/snmp.h deleted file mode 100755 index 15b154e..0000000 --- a/core/c/include/lwip/apps/snmp.h +++ /dev/null @@ -1,135 +0,0 @@ -/** - * @file - * SNMP server main API - start and basic configuration - */ - -/* - * 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 - * Martin Hentschel - * - */ -#ifndef LWIP_HDR_APPS_SNMP_H -#define LWIP_HDR_APPS_SNMP_H - -#include "lwip/apps/snmp_opts.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/err.h" -#include "lwip/apps/snmp_core.h" - -/** SNMP variable binding descriptor (publically needed for traps) */ -struct snmp_varbind -{ - /** pointer to next varbind, NULL for last in list */ - struct snmp_varbind *next; - /** pointer to previous varbind, NULL for first in list */ - struct snmp_varbind *prev; - - /** object identifier */ - struct snmp_obj_id oid; - - /** value ASN1 type */ - u8_t type; - /** object value length */ - u16_t value_len; - /** object value */ - void *value; -}; - -/** - * @ingroup snmp_core - * Agent setup, start listening to port 161. - */ -void snmp_init(void); -void snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs); - -void snmp_set_device_enterprise_oid(const struct snmp_obj_id* device_enterprise_oid); -const struct snmp_obj_id* snmp_get_device_enterprise_oid(void); - -void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable); -void snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst); - -/** Generic trap: cold start */ -#define SNMP_GENTRAP_COLDSTART 0 -/** Generic trap: warm start */ -#define SNMP_GENTRAP_WARMSTART 1 -/** Generic trap: link down */ -#define SNMP_GENTRAP_LINKDOWN 2 -/** Generic trap: link up */ -#define SNMP_GENTRAP_LINKUP 3 -/** Generic trap: authentication failure */ -#define SNMP_GENTRAP_AUTH_FAILURE 4 -/** Generic trap: EGP neighbor lost */ -#define SNMP_GENTRAP_EGP_NEIGHBOR_LOSS 5 -/** Generic trap: enterprise specific */ -#define SNMP_GENTRAP_ENTERPRISE_SPECIFIC 6 - -err_t snmp_send_trap_generic(s32_t generic_trap); -err_t snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds); -err_t snmp_send_trap(const struct snmp_obj_id* oid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds); - -#define SNMP_AUTH_TRAPS_DISABLED 0 -#define SNMP_AUTH_TRAPS_ENABLED 1 -void snmp_set_auth_traps_enabled(u8_t enable); -u8_t snmp_get_auth_traps_enabled(void); - -u8_t snmp_v1_enabled(void); -u8_t snmp_v2c_enabled(void); -u8_t snmp_v3_enabled(void); -void snmp_v1_enable(u8_t enable); -void snmp_v2c_enable(u8_t enable); -void snmp_v3_enable(u8_t enable); - -const char * snmp_get_community(void); -const char * snmp_get_community_write(void); -const char * snmp_get_community_trap(void); -void snmp_set_community(const char * const community); -void snmp_set_community_write(const char * const community); -void snmp_set_community_trap(const char * const community); - -void snmp_coldstart_trap(void); -void snmp_authfail_trap(void); - -typedef void (*snmp_write_callback_fct)(const u32_t* oid, u8_t oid_len, void* callback_arg); -void snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg); - -#endif /* LWIP_SNMP */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_SNMP_H */ diff --git a/core/c/include/lwip/apps/snmp_core.h b/core/c/include/lwip/apps/snmp_core.h deleted file mode 100755 index 4748df6..0000000 --- a/core/c/include/lwip/apps/snmp_core.h +++ /dev/null @@ -1,377 +0,0 @@ -/** - * @file - * SNMP core API for implementing MIBs - */ - -/* - * 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 - * Martin Hentschel - */ - -#ifndef LWIP_HDR_APPS_SNMP_CORE_H -#define LWIP_HDR_APPS_SNMP_CORE_H - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/ip_addr.h" -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* basic ASN1 defines */ -#define SNMP_ASN1_CLASS_UNIVERSAL 0x00 -#define SNMP_ASN1_CLASS_APPLICATION 0x40 -#define SNMP_ASN1_CLASS_CONTEXT 0x80 -#define SNMP_ASN1_CLASS_PRIVATE 0xC0 - -#define SNMP_ASN1_CONTENTTYPE_PRIMITIVE 0x00 -#define SNMP_ASN1_CONTENTTYPE_CONSTRUCTED 0x20 - -/* universal tags (from ASN.1 spec.) */ -#define SNMP_ASN1_UNIVERSAL_END_OF_CONTENT 0 -#define SNMP_ASN1_UNIVERSAL_INTEGER 2 -#define SNMP_ASN1_UNIVERSAL_OCTET_STRING 4 -#define SNMP_ASN1_UNIVERSAL_NULL 5 -#define SNMP_ASN1_UNIVERSAL_OBJECT_ID 6 -#define SNMP_ASN1_UNIVERSAL_SEQUENCE_OF 16 - -/* application specific (SNMP) tags (from SNMPv2-SMI) */ -#define SNMP_ASN1_APPLICATION_IPADDR 0 /* [APPLICATION 0] IMPLICIT OCTET STRING (SIZE (4)) */ -#define SNMP_ASN1_APPLICATION_COUNTER 1 /* [APPLICATION 1] IMPLICIT INTEGER (0..4294967295) => u32_t */ -#define SNMP_ASN1_APPLICATION_GAUGE 2 /* [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) => u32_t */ -#define SNMP_ASN1_APPLICATION_TIMETICKS 3 /* [APPLICATION 3] IMPLICIT INTEGER (0..4294967295) => u32_t */ -#define SNMP_ASN1_APPLICATION_OPAQUE 4 /* [APPLICATION 4] IMPLICIT OCTET STRING */ -#define SNMP_ASN1_APPLICATION_COUNTER64 6 /* [APPLICATION 6] IMPLICIT INTEGER (0..18446744073709551615) */ - -/* context specific (SNMP) tags (from RFC 1905) */ -#define SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_INSTANCE 1 - -/* full ASN1 type defines */ -#define SNMP_ASN1_TYPE_END_OF_CONTENT (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_END_OF_CONTENT) -#define SNMP_ASN1_TYPE_INTEGER (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_INTEGER) -#define SNMP_ASN1_TYPE_OCTET_STRING (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_OCTET_STRING) -#define SNMP_ASN1_TYPE_NULL (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_NULL) -#define SNMP_ASN1_TYPE_OBJECT_ID (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_OBJECT_ID) -#define SNMP_ASN1_TYPE_SEQUENCE (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_UNIVERSAL_SEQUENCE_OF) -#define SNMP_ASN1_TYPE_IPADDR (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_IPADDR) -#define SNMP_ASN1_TYPE_IPADDRESS SNMP_ASN1_TYPE_IPADDR -#define SNMP_ASN1_TYPE_COUNTER (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_COUNTER) -#define SNMP_ASN1_TYPE_COUNTER32 SNMP_ASN1_TYPE_COUNTER -#define SNMP_ASN1_TYPE_GAUGE (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_GAUGE) -#define SNMP_ASN1_TYPE_GAUGE32 SNMP_ASN1_TYPE_GAUGE -#define SNMP_ASN1_TYPE_UNSIGNED32 SNMP_ASN1_TYPE_GAUGE -#define SNMP_ASN1_TYPE_TIMETICKS (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_TIMETICKS) -#define SNMP_ASN1_TYPE_OPAQUE (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_OPAQUE) -#if LWIP_HAVE_INT64 -#define SNMP_ASN1_TYPE_COUNTER64 (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_COUNTER64) -#endif - -#define SNMP_VARBIND_EXCEPTION_OFFSET 0xF0 -#define SNMP_VARBIND_EXCEPTION_MASK 0x0F - -/** error codes predefined by SNMP prot. */ -typedef enum { - SNMP_ERR_NOERROR = 0, -/* -outdated v1 error codes. do not use anmore! -#define SNMP_ERR_NOSUCHNAME 2 use SNMP_ERR_NOSUCHINSTANCE instead -#define SNMP_ERR_BADVALUE 3 use SNMP_ERR_WRONGTYPE,SNMP_ERR_WRONGLENGTH,SNMP_ERR_WRONGENCODING or SNMP_ERR_WRONGVALUE instead -#define SNMP_ERR_READONLY 4 use SNMP_ERR_NOTWRITABLE instead -*/ - SNMP_ERR_GENERROR = 5, - SNMP_ERR_NOACCESS = 6, - SNMP_ERR_WRONGTYPE = 7, - SNMP_ERR_WRONGLENGTH = 8, - SNMP_ERR_WRONGENCODING = 9, - SNMP_ERR_WRONGVALUE = 10, - SNMP_ERR_NOCREATION = 11, - SNMP_ERR_INCONSISTENTVALUE = 12, - SNMP_ERR_RESOURCEUNAVAILABLE = 13, - SNMP_ERR_COMMITFAILED = 14, - SNMP_ERR_UNDOFAILED = 15, - SNMP_ERR_NOTWRITABLE = 17, - SNMP_ERR_INCONSISTENTNAME = 18, - - SNMP_ERR_NOSUCHINSTANCE = SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_INSTANCE -} snmp_err_t; - -/** internal object identifier representation */ -struct snmp_obj_id -{ - u8_t len; - u32_t id[SNMP_MAX_OBJ_ID_LEN]; -}; - -struct snmp_obj_id_const_ref -{ - u8_t len; - const u32_t* id; -}; - -extern const struct snmp_obj_id_const_ref snmp_zero_dot_zero; /* administrative identifier from SNMPv2-SMI */ - -/** SNMP variant value, used as reference in struct snmp_node_instance and table implementation */ -union snmp_variant_value -{ - void* ptr; - const void* const_ptr; - u32_t u32; - s32_t s32; -#if LWIP_HAVE_INT64 - u64_t u64; -#endif -}; - - -/** -SNMP MIB node types - tree node is the only node the stack can process in order to walk the tree, - all other nodes are assumed to be leaf nodes. - This cannot be an enum because users may want to define their own node types. -*/ -#define SNMP_NODE_TREE 0x00 -/* predefined leaf node types */ -#define SNMP_NODE_SCALAR 0x01 -#define SNMP_NODE_SCALAR_ARRAY 0x02 -#define SNMP_NODE_TABLE 0x03 -#define SNMP_NODE_THREADSYNC 0x04 - -/** node "base class" layout, the mandatory fields for a node */ -struct snmp_node -{ - /** one out of SNMP_NODE_TREE or any leaf node type (like SNMP_NODE_SCALAR) */ - u8_t node_type; - /** the number assigned to this node which used as part of the full OID */ - u32_t oid; -}; - -/** SNMP node instance access types */ -typedef enum { - SNMP_NODE_INSTANCE_ACCESS_READ = 1, - SNMP_NODE_INSTANCE_ACCESS_WRITE = 2, - SNMP_NODE_INSTANCE_READ_ONLY = SNMP_NODE_INSTANCE_ACCESS_READ, - SNMP_NODE_INSTANCE_READ_WRITE = (SNMP_NODE_INSTANCE_ACCESS_READ | SNMP_NODE_INSTANCE_ACCESS_WRITE), - SNMP_NODE_INSTANCE_WRITE_ONLY = SNMP_NODE_INSTANCE_ACCESS_WRITE, - SNMP_NODE_INSTANCE_NOT_ACCESSIBLE = 0 -} snmp_access_t; - -struct snmp_node_instance; - -typedef s16_t (*node_instance_get_value_method)(struct snmp_node_instance*, void*); -typedef snmp_err_t (*node_instance_set_test_method)(struct snmp_node_instance*, u16_t, void*); -typedef snmp_err_t (*node_instance_set_value_method)(struct snmp_node_instance*, u16_t, void*); -typedef void (*node_instance_release_method)(struct snmp_node_instance*); - -#define SNMP_GET_VALUE_RAW_DATA 0x4000 /* do not use 0x8000 because return value of node_instance_get_value_method is signed16 and 0x8000 would be the signed bit */ - -/** SNMP node instance */ -struct snmp_node_instance -{ - /** prefilled with the node, get_instance() is called on; may be changed by user to any value to pass an arbitrary node between calls to get_instance() and get_value/test_value/set_value */ - const struct snmp_node* node; - /** prefilled with the instance id requested; for get_instance() this is the exact oid requested; for get_next_instance() this is the relative starting point, stack expects relative oid of next node here */ - struct snmp_obj_id instance_oid; - - /** ASN type for this object (see snmp_asn1.h for definitions) */ - u8_t asn1_type; - /** one out of instance access types defined above (SNMP_NODE_INSTANCE_READ_ONLY,...) */ - snmp_access_t access; - - /** returns object value for the given object identifier. Return values <0 to indicate an error */ - node_instance_get_value_method get_value; - /** tests length and/or range BEFORE setting */ - node_instance_set_test_method set_test; - /** sets object value, only called when set_test() was successful */ - node_instance_set_value_method set_value; - /** called in any case when the instance is not required anymore by stack (useful for freeing memory allocated in get_instance/get_next_instance methods) */ - node_instance_release_method release_instance; - - /** reference to pass arbitrary value between calls to get_instance() and get_value/test_value/set_value */ - union snmp_variant_value reference; - /** see reference (if reference is a pointer, the length of underlying data may be stored here or anything else) */ - u32_t reference_len; -}; - - -/** SNMP tree node */ -struct snmp_tree_node -{ - /** inherited "base class" members */ - struct snmp_node node; - u16_t subnode_count; - const struct snmp_node* const *subnodes; -}; - -#define SNMP_CREATE_TREE_NODE(oid, subnodes) \ - {{ SNMP_NODE_TREE, (oid) }, \ - (u16_t)LWIP_ARRAYSIZE(subnodes), (subnodes) } - -#define SNMP_CREATE_EMPTY_TREE_NODE(oid) \ - {{ SNMP_NODE_TREE, (oid) }, \ - 0, NULL } - -/** SNMP leaf node */ -struct snmp_leaf_node -{ - /** inherited "base class" members */ - struct snmp_node node; - snmp_err_t (*get_instance)(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); - snmp_err_t (*get_next_instance)(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); -}; - -/** represents a single mib with its base oid and root node */ -struct snmp_mib -{ - const u32_t *base_oid; - u8_t base_oid_len; - const struct snmp_node *root_node; -}; - -#define SNMP_MIB_CREATE(oid_list, root_node) { (oid_list), (u8_t)LWIP_ARRAYSIZE(oid_list), root_node } - -/** OID range structure */ -struct snmp_oid_range -{ - u32_t min; - u32_t max; -}; - -/** checks if incoming OID length and values are in allowed ranges */ -u8_t snmp_oid_in_range(const u32_t *oid_in, u8_t oid_len, const struct snmp_oid_range *oid_ranges, u8_t oid_ranges_len); - -typedef enum { - SNMP_NEXT_OID_STATUS_SUCCESS, - SNMP_NEXT_OID_STATUS_NO_MATCH, - SNMP_NEXT_OID_STATUS_BUF_TO_SMALL -} snmp_next_oid_status_t; - -/** state for next_oid_init / next_oid_check functions */ -struct snmp_next_oid_state -{ - const u32_t* start_oid; - u8_t start_oid_len; - - u32_t* next_oid; - u8_t next_oid_len; - u8_t next_oid_max_len; - - snmp_next_oid_status_t status; - void* reference; -}; - -void snmp_next_oid_init(struct snmp_next_oid_state *state, - const u32_t *start_oid, u8_t start_oid_len, - u32_t *next_oid_buf, u8_t next_oid_max_len); -u8_t snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, u8_t oid_len); -u8_t snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, u8_t oid_len, void* reference); - -void snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len); -void snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len); -void snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len); -void snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len); -u8_t snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len); -s8_t snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len); - -#if LWIP_IPV4 -u8_t snmp_oid_to_ip4(const u32_t *oid, ip4_addr_t *ip); -void snmp_ip4_to_oid(const ip4_addr_t *ip, u32_t *oid); -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 -u8_t snmp_oid_to_ip6(const u32_t *oid, ip6_addr_t *ip); -void snmp_ip6_to_oid(const ip6_addr_t *ip, u32_t *oid); -#endif /* LWIP_IPV6 */ -#if LWIP_IPV4 || LWIP_IPV6 -u8_t snmp_ip_to_oid(const ip_addr_t *ip, u32_t *oid); -u8_t snmp_ip_port_to_oid(const ip_addr_t *ip, u16_t port, u32_t *oid); - -u8_t snmp_oid_to_ip(const u32_t *oid, u8_t oid_len, ip_addr_t *ip); -u8_t snmp_oid_to_ip_port(const u32_t *oid, u8_t oid_len, ip_addr_t *ip, u16_t *port); -#endif /* LWIP_IPV4 || LWIP_IPV6 */ - -struct netif; -u8_t netif_to_num(const struct netif *netif); - -snmp_err_t snmp_set_test_ok(struct snmp_node_instance* instance, u16_t value_len, void* value); /* generic function which can be used if test is always successful */ - -err_t snmp_decode_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value); -err_t snmp_decode_truthvalue(const s32_t *asn1_value, u8_t *bool_value); -u8_t snmp_encode_bits(u8_t *buf, u32_t buf_len, u32_t bit_value, u8_t bit_count); -u8_t snmp_encode_truthvalue(s32_t *asn1_value, u32_t bool_value); - -struct snmp_statistics -{ - u32_t inpkts; - u32_t outpkts; - u32_t inbadversions; - u32_t inbadcommunitynames; - u32_t inbadcommunityuses; - u32_t inasnparseerrs; - u32_t intoobigs; - u32_t innosuchnames; - u32_t inbadvalues; - u32_t inreadonlys; - u32_t ingenerrs; - u32_t intotalreqvars; - u32_t intotalsetvars; - u32_t ingetrequests; - u32_t ingetnexts; - u32_t insetrequests; - u32_t ingetresponses; - u32_t intraps; - u32_t outtoobigs; - u32_t outnosuchnames; - u32_t outbadvalues; - u32_t outgenerrs; - u32_t outgetrequests; - u32_t outgetnexts; - u32_t outsetrequests; - u32_t outgetresponses; - u32_t outtraps; -#if LWIP_SNMP_V3 - u32_t unsupportedseclevels; - u32_t notintimewindows; - u32_t unknownusernames; - u32_t unknownengineids; - u32_t wrongdigests; - u32_t decryptionerrors; -#endif -}; - -extern struct snmp_statistics snmp_stats; - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SNMP */ - -#endif /* LWIP_HDR_APPS_SNMP_CORE_H */ diff --git a/core/c/include/lwip/apps/snmp_mib2.h b/core/c/include/lwip/apps/snmp_mib2.h deleted file mode 100755 index 392ee25..0000000 --- a/core/c/include/lwip/apps/snmp_mib2.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @file - * SNMP MIB2 API - */ - -/* - * 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: Dirk Ziegelmeier - * - */ -#ifndef LWIP_HDR_APPS_SNMP_MIB2_H -#define LWIP_HDR_APPS_SNMP_MIB2_H - -#include "lwip/apps/snmp_opts.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ -#if SNMP_LWIP_MIB2 - -#include "lwip/apps/snmp_core.h" - -extern const struct snmp_mib mib2; - -#if SNMP_USE_NETCONN -#include "lwip/apps/snmp_threadsync.h" -void snmp_mib2_lwip_synchronizer(snmp_threadsync_called_fn fn, void* arg); -extern struct snmp_threadsync_instance snmp_mib2_lwip_locks; -#endif - -#ifndef SNMP_SYSSERVICES -#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2)) -#endif - -void snmp_mib2_set_sysdescr(const u8_t* str, const u16_t* len); /* read-only be defintion */ -void snmp_mib2_set_syscontact(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); -void snmp_mib2_set_syscontact_readonly(const u8_t *ocstr, const u16_t *ocstrlen); -void snmp_mib2_set_sysname(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); -void snmp_mib2_set_sysname_readonly(const u8_t *ocstr, const u16_t *ocstrlen); -void snmp_mib2_set_syslocation(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); -void snmp_mib2_set_syslocation_readonly(const u8_t *ocstr, const u16_t *ocstrlen); - -#endif /* SNMP_LWIP_MIB2 */ -#endif /* LWIP_SNMP */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_SNMP_MIB2_H */ diff --git a/core/c/include/lwip/apps/snmp_opts.h b/core/c/include/lwip/apps/snmp_opts.h deleted file mode 100755 index 1c63504..0000000 --- a/core/c/include/lwip/apps/snmp_opts.h +++ /dev/null @@ -1,297 +0,0 @@ -/** - * @file - * SNMP server options list - */ - -/* - * Copyright (c) 2015 Dirk Ziegelmeier - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Dirk Ziegelmeier - * - */ -#ifndef LWIP_HDR_SNMP_OPTS_H -#define LWIP_HDR_SNMP_OPTS_H - -#include "lwip/opt.h" - -/** - * @defgroup snmp_opts Options - * @ingroup snmp - * @{ - */ - -/** - * LWIP_SNMP==1: This enables the lwIP SNMP agent. UDP must be available - * for SNMP transport. - * If you want to use your own SNMP agent, leave this disabled. - * To integrate MIB2 of an external agent, you need to enable - * LWIP_MIB2_CALLBACKS and MIB2_STATS. This will give you the callbacks - * and statistics counters you need to get MIB2 working. - */ -#if !defined LWIP_SNMP || defined __DOXYGEN__ -#define LWIP_SNMP 0 -#endif - -/** - * SNMP_USE_NETCONN: Use netconn API instead of raw API. - * Makes SNMP agent run in a worker thread, so blocking operations - * can be done in MIB calls. - */ -#if !defined SNMP_USE_NETCONN || defined __DOXYGEN__ -#define SNMP_USE_NETCONN 0 -#endif - -/** - * SNMP_USE_RAW: Use raw API. - * SNMP agent does not run in a worker thread, so blocking operations - * should not be done in MIB calls. - */ -#if !defined SNMP_USE_RAW || defined __DOXYGEN__ -#define SNMP_USE_RAW 1 -#endif - -#if SNMP_USE_NETCONN && SNMP_USE_RAW -#error SNMP stack can use only one of the APIs {raw, netconn} -#endif - -#if LWIP_SNMP && !SNMP_USE_NETCONN && !SNMP_USE_RAW -#error SNMP stack needs a receive API and UDP {raw, netconn} -#endif - -#if SNMP_USE_NETCONN -/** - * SNMP_STACK_SIZE: Stack size of SNMP netconn worker thread - */ -#if !defined SNMP_STACK_SIZE || defined __DOXYGEN__ -#define SNMP_STACK_SIZE DEFAULT_THREAD_STACKSIZE -#endif - -/** - * SNMP_THREAD_PRIO: SNMP netconn worker thread priority - */ -#if !defined SNMP_THREAD_PRIO || defined __DOXYGEN__ -#define SNMP_THREAD_PRIO DEFAULT_THREAD_PRIO -#endif -#endif /* SNMP_USE_NETCONN */ - -/** - * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap - * destination is required - */ -#if !defined SNMP_TRAP_DESTINATIONS || defined __DOXYGEN__ -#define SNMP_TRAP_DESTINATIONS 1 -#endif - -/** - * Only allow SNMP write actions that are 'safe' (e.g. disabling netifs is not - * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). - * Unsafe requests are disabled by default! - */ -#if !defined SNMP_SAFE_REQUESTS || defined __DOXYGEN__ -#define SNMP_SAFE_REQUESTS 1 -#endif - -/** - * The maximum length of strings used. - */ -#if !defined SNMP_MAX_OCTET_STRING_LEN || defined __DOXYGEN__ -#define SNMP_MAX_OCTET_STRING_LEN 127 -#endif - -/** - * The maximum number of Sub ID's inside an object identifier. - * Indirectly this also limits the maximum depth of SNMP tree. - */ -#if !defined SNMP_MAX_OBJ_ID_LEN || defined __DOXYGEN__ -#define SNMP_MAX_OBJ_ID_LEN 50 -#endif - -#if !defined SNMP_MAX_VALUE_SIZE || defined __DOXYGEN__ -/** - * The minimum size of a value. - */ -#define SNMP_MIN_VALUE_SIZE (2 * sizeof(u32_t*)) /* size required to store the basic types (8 bytes for counter64) */ -/** - * The maximum size of a value. - */ -#define SNMP_MAX_VALUE_SIZE LWIP_MAX(LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN), sizeof(u32_t)*(SNMP_MAX_OBJ_ID_LEN)), SNMP_MIN_VALUE_SIZE) -#endif - -/** - * The snmp read-access community. Used for write-access and traps, too - * unless SNMP_COMMUNITY_WRITE or SNMP_COMMUNITY_TRAP are enabled, respectively. - */ -#if !defined SNMP_COMMUNITY || defined __DOXYGEN__ -#define SNMP_COMMUNITY "public" -#endif - -/** - * The snmp write-access community. - * Set this community to "" in order to disallow any write access. - */ -#if !defined SNMP_COMMUNITY_WRITE || defined __DOXYGEN__ -#define SNMP_COMMUNITY_WRITE "private" -#endif - -/** - * The snmp community used for sending traps. - */ -#if !defined SNMP_COMMUNITY_TRAP || defined __DOXYGEN__ -#define SNMP_COMMUNITY_TRAP "public" -#endif - -/** - * The maximum length of community string. - * If community names shall be adjusted at runtime via snmp_set_community() calls, - * enter here the possible maximum length (+1 for terminating null character). - */ -#if !defined SNMP_MAX_COMMUNITY_STR_LEN || defined __DOXYGEN__ -#define SNMP_MAX_COMMUNITY_STR_LEN LWIP_MAX(LWIP_MAX(sizeof(SNMP_COMMUNITY), sizeof(SNMP_COMMUNITY_WRITE)), sizeof(SNMP_COMMUNITY_TRAP)) -#endif - -/** - * The OID identifiying the device. This may be the enterprise OID itself or any OID located below it in tree. - */ -#if !defined SNMP_DEVICE_ENTERPRISE_OID || defined __DOXYGEN__ -#define SNMP_LWIP_ENTERPRISE_OID 26381 -/** - * IANA assigned enterprise ID for lwIP is 26381 - * @see http://www.iana.org/assignments/enterprise-numbers - * - * @note this enterprise ID is assigned to the lwIP project, - * all object identifiers living under this ID are assigned - * by the lwIP maintainers! - * @note don't change this define, use snmp_set_device_enterprise_oid() - * - * If you need to create your own private MIB you'll need - * to apply for your own enterprise ID with IANA: - * http://www.iana.org/numbers.html - */ -#define SNMP_DEVICE_ENTERPRISE_OID {1, 3, 6, 1, 4, 1, SNMP_LWIP_ENTERPRISE_OID} -/** - * Length of SNMP_DEVICE_ENTERPRISE_OID - */ -#define SNMP_DEVICE_ENTERPRISE_OID_LEN 7 -#endif - -/** - * SNMP_DEBUG: Enable debugging for SNMP messages. - */ -#if !defined SNMP_DEBUG || defined __DOXYGEN__ -#define SNMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. - */ -#if !defined SNMP_MIB_DEBUG || defined __DOXYGEN__ -#define SNMP_MIB_DEBUG LWIP_DBG_OFF -#endif - -/** - * Indicates if the MIB2 implementation of LWIP SNMP stack is used. - */ -#if !defined SNMP_LWIP_MIB2 || defined __DOXYGEN__ -#define SNMP_LWIP_MIB2 LWIP_SNMP -#endif - -/** - * Value return for sysDesc field of MIB2. - */ -#if !defined SNMP_LWIP_MIB2_SYSDESC || defined __DOXYGEN__ -#define SNMP_LWIP_MIB2_SYSDESC "lwIP" -#endif - -/** - * Value return for sysName field of MIB2. - * To make sysName field settable, call snmp_mib2_set_sysname() to provide the necessary buffers. - */ -#if !defined SNMP_LWIP_MIB2_SYSNAME || defined __DOXYGEN__ -#define SNMP_LWIP_MIB2_SYSNAME "FQDN-unk" -#endif - -/** - * Value return for sysContact field of MIB2. - * To make sysContact field settable, call snmp_mib2_set_syscontact() to provide the necessary buffers. - */ -#if !defined SNMP_LWIP_MIB2_SYSCONTACT || defined __DOXYGEN__ -#define SNMP_LWIP_MIB2_SYSCONTACT "" -#endif - -/** - * Value return for sysLocation field of MIB2. - * To make sysLocation field settable, call snmp_mib2_set_syslocation() to provide the necessary buffers. - */ -#if !defined SNMP_LWIP_MIB2_SYSLOCATION || defined __DOXYGEN__ -#define SNMP_LWIP_MIB2_SYSLOCATION "" -#endif - -/** - * This value is used to limit the repetitions processed in GetBulk requests (value == 0 means no limitation). - * This may be useful to limit the load for a single request. - * According to SNMP RFC 1905 it is allowed to not return all requested variables from a GetBulk request if system load would be too high. - * so the effect is that the client will do more requests to gather all data. - * For the stack this could be useful in case that SNMP processing is done in TCP/IP thread. In this situation a request with many - * repetitions could block the thread for a longer time. Setting limit here will keep the stack more responsive. - */ -#if !defined SNMP_LWIP_GETBULK_MAX_REPETITIONS || defined __DOXYGEN__ -#define SNMP_LWIP_GETBULK_MAX_REPETITIONS 0 -#endif - -/** - * @} - */ - -/* - ------------------------------------ - ---------- SNMPv3 options ---------- - ------------------------------------ -*/ - -/** - * LWIP_SNMP_V3==1: This enables EXPERIMENTAL SNMPv3 support. LWIP_SNMP must - * also be enabled. - * THIS IS UNDER DEVELOPMENT AND SHOULD NOT BE ENABLED IN PRODUCTS. - */ -#ifndef LWIP_SNMP_V3 -#define LWIP_SNMP_V3 0 -#endif - -#ifndef LWIP_SNMP_V3_MBEDTLS -#define LWIP_SNMP_V3_MBEDTLS LWIP_SNMP_V3 -#endif - -#ifndef LWIP_SNMP_V3_CRYPTO -#define LWIP_SNMP_V3_CRYPTO LWIP_SNMP_V3_MBEDTLS -#endif - -#ifndef LWIP_SNMP_CONFIGURE_VERSIONS -#define LWIP_SNMP_CONFIGURE_VERSIONS 0 -#endif - -#endif /* LWIP_HDR_SNMP_OPTS_H */ diff --git a/core/c/include/lwip/apps/snmp_scalar.h b/core/c/include/lwip/apps/snmp_scalar.h deleted file mode 100755 index 99bcdf9..0000000 --- a/core/c/include/lwip/apps/snmp_scalar.h +++ /dev/null @@ -1,113 +0,0 @@ -/** - * @file - * SNMP server MIB API to implement scalar nodes - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Martin Hentschel - * - */ - -#ifndef LWIP_HDR_APPS_SNMP_SCALAR_H -#define LWIP_HDR_APPS_SNMP_SCALAR_H - -#include "lwip/apps/snmp_opts.h" -#include "lwip/apps/snmp_core.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -/** basic scalar node */ -struct snmp_scalar_node -{ - /** inherited "base class" members */ - struct snmp_leaf_node node; - u8_t asn1_type; - snmp_access_t access; - node_instance_get_value_method get_value; - node_instance_set_test_method set_test; - node_instance_set_value_method set_value; -}; - - -snmp_err_t snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); -snmp_err_t snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); - -#define SNMP_SCALAR_CREATE_NODE(oid, access, asn1_type, get_value_method, set_test_method, set_value_method) \ - {{{ SNMP_NODE_SCALAR, (oid) }, \ - snmp_scalar_get_instance, \ - snmp_scalar_get_next_instance }, \ - (asn1_type), (access), (get_value_method), (set_test_method), (set_value_method) } - -#define SNMP_SCALAR_CREATE_NODE_READONLY(oid, asn1_type, get_value_method) SNMP_SCALAR_CREATE_NODE(oid, SNMP_NODE_INSTANCE_READ_ONLY, asn1_type, get_value_method, NULL, NULL) - -/** scalar array node - a tree node which contains scalars only as children */ -struct snmp_scalar_array_node_def -{ - u32_t oid; - u8_t asn1_type; - snmp_access_t access; -}; - -typedef s16_t (*snmp_scalar_array_get_value_method)(const struct snmp_scalar_array_node_def*, void*); -typedef snmp_err_t (*snmp_scalar_array_set_test_method)(const struct snmp_scalar_array_node_def*, u16_t, void*); -typedef snmp_err_t (*snmp_scalar_array_set_value_method)(const struct snmp_scalar_array_node_def*, u16_t, void*); - -/** basic scalar array node */ -struct snmp_scalar_array_node -{ - /** inherited "base class" members */ - struct snmp_leaf_node node; - u16_t array_node_count; - const struct snmp_scalar_array_node_def* array_nodes; - snmp_scalar_array_get_value_method get_value; - snmp_scalar_array_set_test_method set_test; - snmp_scalar_array_set_value_method set_value; -}; - -snmp_err_t snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); -snmp_err_t snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); - -#define SNMP_SCALAR_CREATE_ARRAY_NODE(oid, array_nodes, get_value_method, set_test_method, set_value_method) \ - {{{ SNMP_NODE_SCALAR_ARRAY, (oid) }, \ - snmp_scalar_array_get_instance, \ - snmp_scalar_array_get_next_instance }, \ - (u16_t)LWIP_ARRAYSIZE(array_nodes), (array_nodes), (get_value_method), (set_test_method), (set_value_method) } - -#endif /* LWIP_SNMP */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_SNMP_SCALAR_H */ diff --git a/core/c/include/lwip/apps/snmp_snmpv2_framework.h b/core/c/include/lwip/apps/snmp_snmpv2_framework.h deleted file mode 100755 index 9f4b41c..0000000 --- a/core/c/include/lwip/apps/snmp_snmpv2_framework.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -Generated by LwipMibCompiler -*/ - -#ifndef LWIP_HDR_APPS_SNMP_FRAMEWORK_MIB_H -#define LWIP_HDR_APPS_SNMP_FRAMEWORK_MIB_H - -#include "lwip/apps/snmp_opts.h" -#if LWIP_SNMP - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include "lwip/apps/snmp_core.h" - -extern const struct snmp_obj_id usmNoAuthProtocol; -extern const struct snmp_obj_id usmHMACMD5AuthProtocol; -extern const struct snmp_obj_id usmHMACSHAAuthProtocol; - -extern const struct snmp_obj_id usmNoPrivProtocol; -extern const struct snmp_obj_id usmDESPrivProtocol; -extern const struct snmp_obj_id usmAESPrivProtocol; - -extern const struct snmp_mib snmpframeworkmib; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* LWIP_SNMP */ -#endif /* LWIP_HDR_APPS_SNMP_FRAMEWORK_MIB_H */ diff --git a/core/c/include/lwip/apps/snmp_snmpv2_usm.h b/core/c/include/lwip/apps/snmp_snmpv2_usm.h deleted file mode 100755 index ae09baa..0000000 --- a/core/c/include/lwip/apps/snmp_snmpv2_usm.h +++ /dev/null @@ -1,24 +0,0 @@ -/* -Generated by LwipMibCompiler -*/ - -#ifndef LWIP_HDR_APPS_SNMP_USER_BASED_SM_MIB_H -#define LWIP_HDR_APPS_SNMP_USER_BASED_SM_MIB_H - -#include "lwip/apps/snmp_opts.h" -#if LWIP_SNMP - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include "lwip/apps/snmp_core.h" - -extern const struct snmp_mib snmpusmmib; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* LWIP_SNMP */ -#endif /* LWIP_HDR_APPS_SNMP_USER_BASED_SM_MIB_H */ diff --git a/core/c/include/lwip/apps/snmp_table.h b/core/c/include/lwip/apps/snmp_table.h deleted file mode 100755 index 6930d0b..0000000 --- a/core/c/include/lwip/apps/snmp_table.h +++ /dev/null @@ -1,134 +0,0 @@ -/** - * @file - * SNMP server MIB API to implement table nodes - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Martin Hentschel - * - */ - -#ifndef LWIP_HDR_APPS_SNMP_TABLE_H -#define LWIP_HDR_APPS_SNMP_TABLE_H - -#include "lwip/apps/snmp_opts.h" -#include "lwip/apps/snmp_core.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -/** default (customizable) read/write table */ -struct snmp_table_col_def -{ - u32_t index; - u8_t asn1_type; - snmp_access_t access; -}; - -/** table node */ -struct snmp_table_node -{ - /** inherited "base class" members */ - struct snmp_leaf_node node; - u16_t column_count; - const struct snmp_table_col_def* columns; - snmp_err_t (*get_cell_instance)(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance); - snmp_err_t (*get_next_cell_instance)(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance); - /** returns object value for the given object identifier */ - node_instance_get_value_method get_value; - /** tests length and/or range BEFORE setting */ - node_instance_set_test_method set_test; - /** sets object value, only called when set_test() was successful */ - node_instance_set_value_method set_value; -}; - -snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); -snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); - -#define SNMP_TABLE_CREATE(oid, columns, get_cell_instance_method, get_next_cell_instance_method, get_value_method, set_test_method, set_value_method) \ - {{{ SNMP_NODE_TABLE, (oid) }, \ - snmp_table_get_instance, \ - snmp_table_get_next_instance }, \ - (u16_t)LWIP_ARRAYSIZE(columns), (columns), \ - (get_cell_instance_method), (get_next_cell_instance_method), \ - (get_value_method), (set_test_method), (set_value_method)} - -#define SNMP_TABLE_GET_COLUMN_FROM_OID(oid) ((oid)[1]) /* first array value is (fixed) row entry (fixed to 1) and 2nd value is column, follow3ed by instance */ - - -/** simple read-only table */ -typedef enum { - SNMP_VARIANT_VALUE_TYPE_U32, - SNMP_VARIANT_VALUE_TYPE_S32, - SNMP_VARIANT_VALUE_TYPE_PTR, - SNMP_VARIANT_VALUE_TYPE_CONST_PTR -} snmp_table_column_data_type_t; - -struct snmp_table_simple_col_def -{ - u32_t index; - u8_t asn1_type; - snmp_table_column_data_type_t data_type; /* depending of what union member is used to store the value*/ -}; - -/** simple read-only table node */ -struct snmp_table_simple_node -{ - /* inherited "base class" members */ - struct snmp_leaf_node node; - u16_t column_count; - const struct snmp_table_simple_col_def* columns; - snmp_err_t (*get_cell_value)(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len); - snmp_err_t (*get_next_cell_instance_and_value)(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len); -}; - -snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); -snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); - -#define SNMP_TABLE_CREATE_SIMPLE(oid, columns, get_cell_value_method, get_next_cell_instance_and_value_method) \ - {{{ SNMP_NODE_TABLE, (oid) }, \ - snmp_table_simple_get_instance, \ - snmp_table_simple_get_next_instance }, \ - (u16_t)LWIP_ARRAYSIZE(columns), (columns), (get_cell_value_method), (get_next_cell_instance_and_value_method) } - -s16_t snmp_table_extract_value_from_s32ref(struct snmp_node_instance* instance, void* value); -s16_t snmp_table_extract_value_from_u32ref(struct snmp_node_instance* instance, void* value); -s16_t snmp_table_extract_value_from_refconstptr(struct snmp_node_instance* instance, void* value); - -#endif /* LWIP_SNMP */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_SNMP_TABLE_H */ diff --git a/core/c/include/lwip/apps/snmp_threadsync.h b/core/c/include/lwip/apps/snmp_threadsync.h deleted file mode 100755 index 5eb3538..0000000 --- a/core/c/include/lwip/apps/snmp_threadsync.h +++ /dev/null @@ -1,114 +0,0 @@ -/** - * @file - * SNMP server MIB API to implement thread synchronization - */ - -/* - * 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: Dirk Ziegelmeier - * - */ - -#ifndef LWIP_HDR_APPS_SNMP_THREADSYNC_H -#define LWIP_HDR_APPS_SNMP_THREADSYNC_H - -#include "lwip/apps/snmp_opts.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/apps/snmp_core.h" -#include "lwip/sys.h" - -typedef void (*snmp_threadsync_called_fn)(void* arg); -typedef void (*snmp_threadsync_synchronizer_fn)(snmp_threadsync_called_fn fn, void* arg); - - -/** Thread sync runtime data. For internal usage only. */ -struct threadsync_data -{ - union { - snmp_err_t err; - s16_t s16; - } retval; - union { - const u32_t *root_oid; - void *value; - } arg1; - union { - u8_t root_oid_len; - u16_t len; - } arg2; - const struct snmp_threadsync_node *threadsync_node; - struct snmp_node_instance proxy_instance; -}; - -/** Thread sync instance. Needed EXCATLY once for every thread to be synced into. */ -struct snmp_threadsync_instance -{ - sys_sem_t sem; - sys_mutex_t sem_usage_mutex; - snmp_threadsync_synchronizer_fn sync_fn; - struct threadsync_data data; -}; - -/** SNMP thread sync proxy leaf node */ -struct snmp_threadsync_node -{ - /* inherited "base class" members */ - struct snmp_leaf_node node; - - const struct snmp_leaf_node *target; - struct snmp_threadsync_instance *instance; -}; - -snmp_err_t snmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); -snmp_err_t snmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); - -/** Create thread sync proxy node */ -#define SNMP_CREATE_THREAD_SYNC_NODE(oid, target_leaf_node, threadsync_instance) \ - {{{ SNMP_NODE_THREADSYNC, (oid) }, \ - snmp_threadsync_get_instance, \ - snmp_threadsync_get_next_instance }, \ - (target_leaf_node), \ - (threadsync_instance) } - -/** Create thread sync instance data */ -void snmp_threadsync_init(struct snmp_threadsync_instance *instance, snmp_threadsync_synchronizer_fn sync_fn); - -#endif /* LWIP_SNMP */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_SNMP_THREADSYNC_H */ diff --git a/core/c/include/lwip/apps/snmpv3.h b/core/c/include/lwip/apps/snmpv3.h deleted file mode 100755 index bd7d314..0000000 --- a/core/c/include/lwip/apps/snmpv3.h +++ /dev/null @@ -1,114 +0,0 @@ -/** - * @file - * Additional SNMPv3 functionality RFC3414 and RFC3826. - */ - -/* - * Copyright (c) 2016 Elias Oenal. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Elias Oenal - */ - -#ifndef LWIP_HDR_APPS_SNMP_V3_H -#define LWIP_HDR_APPS_SNMP_V3_H - -#include "lwip/apps/snmp_opts.h" -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_SNMP && LWIP_SNMP_V3 - -typedef enum -{ - SNMP_V3_AUTH_ALGO_INVAL = 0, - SNMP_V3_AUTH_ALGO_MD5 = 1, - SNMP_V3_AUTH_ALGO_SHA = 2 -} snmpv3_auth_algo_t; - -typedef enum -{ - SNMP_V3_PRIV_ALGO_INVAL = 0, - SNMP_V3_PRIV_ALGO_DES = 1, - SNMP_V3_PRIV_ALGO_AES = 2 -} snmpv3_priv_algo_t; - -typedef enum -{ - SNMP_V3_USER_STORAGETYPE_OTHER = 1, - SNMP_V3_USER_STORAGETYPE_VOLATILE = 2, - SNMP_V3_USER_STORAGETYPE_NONVOLATILE = 3, - SNMP_V3_USER_STORAGETYPE_PERMANENT = 4, - SNMP_V3_USER_STORAGETYPE_READONLY = 5 -} snmpv3_user_storagetype_t; - -/* - * The following callback functions must be implemented by the application. - * There is a dummy implementation in snmpv3_dummy.c. - */ - -void snmpv3_get_engine_id(const char **id, u8_t *len); -err_t snmpv3_set_engine_id(const char* id, u8_t len); - -u32_t snmpv3_get_engine_boots(void); -void snmpv3_set_engine_boots(u32_t boots); - -u32_t snmpv3_get_engine_time(void); -void snmpv3_reset_engine_time(void); - -err_t snmpv3_get_user(const char* username, snmpv3_auth_algo_t *auth_algo, u8_t *auth_key, snmpv3_priv_algo_t *priv_algo, u8_t *priv_key); -u8_t snmpv3_get_amount_of_users(void); -err_t snmpv3_get_user_storagetype(const char *username, snmpv3_user_storagetype_t *storagetype); -err_t snmpv3_get_username(char *username, u8_t index); - -/* The following functions are provided by the SNMPv3 agent */ - -void snmpv3_engine_id_changed(void); -s32_t snmpv3_get_engine_time_internal(void); - -void snmpv3_password_to_key_md5( - const u8_t *password, /* IN */ - size_t passwordlen, /* IN */ - const u8_t *engineID, /* IN - pointer to snmpEngineID */ - u8_t engineLength, /* IN - length of snmpEngineID */ - u8_t *key); /* OUT - pointer to caller 16-octet buffer */ - -void snmpv3_password_to_key_sha( - const u8_t *password, /* IN */ - size_t passwordlen, /* IN */ - const u8_t *engineID, /* IN - pointer to snmpEngineID */ - u8_t engineLength, /* IN - length of snmpEngineID */ - u8_t *key); /* OUT - pointer to caller 20-octet buffer */ - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_SNMP_V3_H */ diff --git a/core/c/include/lwip/apps/sntp.h b/core/c/include/lwip/apps/sntp.h deleted file mode 100755 index 00135b4..0000000 --- a/core/c/include/lwip/apps/sntp.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file - * SNTP client API - */ - -/* - * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Frédéric Bernon, Simon Goldschmidt - * - */ -#ifndef LWIP_HDR_APPS_SNTP_H -#define LWIP_HDR_APPS_SNTP_H - -#include "lwip/apps/sntp_opts.h" -#include "lwip/ip_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* SNTP operating modes: default is to poll using unicast. - The mode has to be set before calling sntp_init(). */ -#define SNTP_OPMODE_POLL 0 -#define SNTP_OPMODE_LISTENONLY 1 -void sntp_setoperatingmode(u8_t operating_mode); -u8_t sntp_getoperatingmode(void); - -void sntp_init(void); -void sntp_stop(void); -u8_t sntp_enabled(void); - -void sntp_setserver(u8_t idx, const ip_addr_t *addr); -const ip_addr_t* sntp_getserver(u8_t idx); - -#if SNTP_MONITOR_SERVER_REACHABILITY -u8_t sntp_getreachability(u8_t idx); -#endif /* SNTP_MONITOR_SERVER_REACHABILITY */ - -#if SNTP_SERVER_DNS -void sntp_setservername(u8_t idx, const char *server); -const 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_HDR_APPS_SNTP_H */ diff --git a/core/c/include/lwip/apps/sntp_opts.h b/core/c/include/lwip/apps/sntp_opts.h deleted file mode 100755 index c25a386..0000000 --- a/core/c/include/lwip/apps/sntp_opts.h +++ /dev/null @@ -1,209 +0,0 @@ -/** - * @file - * SNTP client options list - */ - -/* - * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Frédéric Bernon, Simon Goldschmidt - * - */ -#ifndef LWIP_HDR_APPS_SNTP_OPTS_H -#define LWIP_HDR_APPS_SNTP_OPTS_H - -#include "lwip/opt.h" -#include "lwip/prot/iana.h" - -/** - * @defgroup sntp_opts Options - * @ingroup sntp - * @{ - */ - -/** SNTP macro to change system time in seconds - * Define SNTP_SET_SYSTEM_TIME_US(sec, us) to set the time in microseconds - * instead of this one if you need the additional precision. Alternatively, - * define SNTP_SET_SYSTEM_TIME_NTP(sec, frac) in order to work with native - * NTP timestamps instead. - */ -#if !defined SNTP_SET_SYSTEM_TIME || defined __DOXYGEN__ -#define SNTP_SET_SYSTEM_TIME(sec) LWIP_UNUSED_ARG(sec) -#endif - -/** The maximum number of SNTP servers that can be set */ -#if !defined SNTP_MAX_SERVERS || defined __DOXYGEN__ -#define SNTP_MAX_SERVERS LWIP_DHCP_MAX_NTP_SERVERS -#endif - -/** Set this to 1 to implement the callback function called by dhcp when - * NTP servers are received. */ -#if !defined SNTP_GET_SERVERS_FROM_DHCP || defined __DOXYGEN__ -#define SNTP_GET_SERVERS_FROM_DHCP LWIP_DHCP_GET_NTP_SRV -#endif - -/** Set this to 1 to support DNS names (or IP address strings) to set sntp servers - * One server address/name can be defined as default if SNTP_SERVER_DNS == 1: - * \#define SNTP_SERVER_ADDRESS "pool.ntp.org" - */ -#if !defined SNTP_SERVER_DNS || defined __DOXYGEN__ -#define SNTP_SERVER_DNS 0 -#endif - -/** - * SNTP_DEBUG: Enable debugging for SNTP. - */ -#if !defined SNTP_DEBUG || defined __DOXYGEN__ -#define SNTP_DEBUG LWIP_DBG_OFF -#endif - -/** SNTP server port */ -#if !defined SNTP_PORT || defined __DOXYGEN__ -#define SNTP_PORT LWIP_IANA_PORT_SNTP -#endif - -/** 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 VN, 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. - */ -#if !defined SNTP_CHECK_RESPONSE || defined __DOXYGEN__ -#define SNTP_CHECK_RESPONSE 0 -#endif - -/** Enable round-trip delay compensation. - * Compensate for the round-trip delay by calculating the clock offset from - * the originate, receive, transmit and destination timestamps, as per RFC. - * - * The calculation requires compiler support for 64-bit integers. Also, either - * SNTP_SET_SYSTEM_TIME_US or SNTP_SET_SYSTEM_TIME_NTP has to be implemented - * for setting the system clock with sub-second precision. Likewise, either - * SNTP_GET_SYSTEM_TIME or SNTP_GET_SYSTEM_TIME_NTP needs to be implemented - * with sub-second precision. - * - * Although not strictly required, it makes sense to combine this option with - * SNTP_CHECK_RESPONSE >= 2 for sanity-checking of the received timestamps. - * Also, in order for the round-trip calculation to work, the difference - * between the local clock and the NTP server clock must not be larger than - * about 34 years. If that limit is exceeded, the implementation will fall back - * to setting the clock without compensation. In order to ensure that the local - * clock is always within the permitted range for compensation, even at first - * try, it may be necessary to store at least the current year in non-volatile - * memory. - */ -#if !defined SNTP_COMP_ROUNDTRIP || defined __DOXYGEN__ -#define SNTP_COMP_ROUNDTRIP 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. - */ -#if !defined SNTP_STARTUP_DELAY || defined __DOXYGEN__ -#ifdef LWIP_RAND -#define SNTP_STARTUP_DELAY 1 -#else -#define SNTP_STARTUP_DELAY 0 -#endif -#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. - */ -#if !defined SNTP_STARTUP_DELAY_FUNC || defined __DOXYGEN__ -#define SNTP_STARTUP_DELAY_FUNC (LWIP_RAND() % 5000) -#endif - -/** SNTP receive timeout - in milliseconds - * Also used as retry timeout - this shouldn't be too low. - * Default is 15 seconds. Must not be beolw 15 seconds by specification (i.e. 15000) - */ -#if !defined SNTP_RECV_TIMEOUT || defined __DOXYGEN__ -#define SNTP_RECV_TIMEOUT 15000 -#endif - -/** SNTP update delay - in milliseconds - * Default is 1 hour. Must not be beolw 60 seconds by specification (i.e. 60000) - */ -#if !defined SNTP_UPDATE_DELAY || defined __DOXYGEN__ -#define SNTP_UPDATE_DELAY 3600000 -#endif - -/** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2 - * to send in request and compare in response. Also used for round-trip - * delay compensation if SNTP_COMP_ROUNDTRIP != 0. - * Alternatively, define SNTP_GET_SYSTEM_TIME_NTP(sec, frac) in order to - * work with native NTP timestamps instead. - */ -#if !defined SNTP_GET_SYSTEM_TIME || defined __DOXYGEN__ -#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. - */ -#if !defined SNTP_RETRY_TIMEOUT || defined __DOXYGEN__ -#define SNTP_RETRY_TIMEOUT SNTP_RECV_TIMEOUT -#endif - -/** Maximum retry timeout (in milliseconds). */ -#if !defined SNTP_RETRY_TIMEOUT_MAX || defined __DOXYGEN__ -#define SNTP_RETRY_TIMEOUT_MAX (SNTP_RETRY_TIMEOUT * 10) -#endif - -/** Increase retry timeout with every retry sent - * Default is on to conform to RFC. - */ -#if !defined SNTP_RETRY_TIMEOUT_EXP || defined __DOXYGEN__ -#define SNTP_RETRY_TIMEOUT_EXP 1 -#endif - -/** Keep a reachability shift register per server - * Default is on to conform to RFC. - */ -#if !defined SNTP_MONITOR_SERVER_REACHABILITY || defined __DOXYGEN__ -#define SNTP_MONITOR_SERVER_REACHABILITY 1 -#endif - -/** - * @} - */ - -#endif /* LWIP_HDR_APPS_SNTP_OPTS_H */ diff --git a/core/c/include/lwip/apps/tftp_opts.h b/core/c/include/lwip/apps/tftp_opts.h deleted file mode 100755 index d187b82..0000000 --- a/core/c/include/lwip/apps/tftp_opts.h +++ /dev/null @@ -1,106 +0,0 @@ -/** - * - * @file tftp_opts.h - * - * @author Logan Gunthorpe - * - * @brief Trivial File Transfer Protocol (RFC 1350) implementation options - * - * Copyright (c) Deltatee Enterprises Ltd. 2013 - * All rights reserved. - * - */ - -/* - * Redistribution and use in source and binary forms, with or without - * modification,are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Logan Gunthorpe - * - */ - -#ifndef LWIP_HDR_APPS_TFTP_OPTS_H -#define LWIP_HDR_APPS_TFTP_OPTS_H - -#include "lwip/opt.h" -#include "lwip/prot/iana.h" - -/** - * @defgroup tftp_opts Options - * @ingroup tftp - * @{ - */ - -/** - * Enable TFTP debug messages - */ -#if !defined TFTP_DEBUG || defined __DOXYGEN__ -#define TFTP_DEBUG LWIP_DBG_OFF -#endif - -/** - * TFTP server port - */ -#if !defined TFTP_PORT || defined __DOXYGEN__ -#define TFTP_PORT LWIP_IANA_PORT_TFTP -#endif - -/** - * TFTP timeout - */ -#if !defined TFTP_TIMEOUT_MSECS || defined __DOXYGEN__ -#define TFTP_TIMEOUT_MSECS 10000 -#endif - -/** - * Max. number of retries when a file is read from server - */ -#if !defined TFTP_MAX_RETRIES || defined __DOXYGEN__ -#define TFTP_MAX_RETRIES 5 -#endif - -/** - * TFTP timer cyclic interval - */ -#if !defined TFTP_TIMER_MSECS || defined __DOXYGEN__ -#define TFTP_TIMER_MSECS (TFTP_TIMEOUT_MSECS / 10) -#endif - -/** - * Max. length of TFTP filename - */ -#if !defined TFTP_MAX_FILENAME_LEN || defined __DOXYGEN__ -#define TFTP_MAX_FILENAME_LEN 20 -#endif - -/** - * Max. length of TFTP mode - */ -#if !defined TFTP_MAX_MODE_LEN || defined __DOXYGEN__ -#define TFTP_MAX_MODE_LEN 7 -#endif - -/** - * @} - */ - -#endif /* LWIP_HDR_APPS_TFTP_OPTS_H */ diff --git a/core/c/include/lwip/apps/tftp_server.h b/core/c/include/lwip/apps/tftp_server.h deleted file mode 100755 index 3ce5e40..0000000 --- a/core/c/include/lwip/apps/tftp_server.h +++ /dev/null @@ -1,95 +0,0 @@ -/** - * - * @file tftp_server.h - * - * @author Logan Gunthorpe - * - * @brief Trivial File Transfer Protocol (RFC 1350) - * - * Copyright (c) Deltatee Enterprises Ltd. 2013 - * All rights reserved. - * - */ - -/* - * Redistribution and use in source and binary forms, with or without - * modification,are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Logan Gunthorpe - * - */ - -#ifndef LWIP_HDR_APPS_TFTP_SERVER_H -#define LWIP_HDR_APPS_TFTP_SERVER_H - -#include "lwip/apps/tftp_opts.h" -#include "lwip/err.h" -#include "lwip/pbuf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** @ingroup tftp - * TFTP context containing callback functions for TFTP transfers - */ -struct tftp_context { - /** - * Open file for read/write. - * @param fname Filename - * @param mode Mode string from TFTP RFC 1350 (netascii, octet, mail) - * @param write Flag indicating read (0) or write (!= 0) access - * @returns File handle supplied to other functions - */ - void* (*open)(const char* fname, const char* mode, u8_t write); - /** - * Close file handle - * @param handle File handle returned by open() - */ - void (*close)(void* handle); - /** - * Read from file - * @param handle File handle returned by open() - * @param buf Target buffer to copy read data to - * @param bytes Number of bytes to copy to buf - * @returns >= 0: Success; < 0: Error - */ - int (*read)(void* handle, void* buf, int bytes); - /** - * Write to file - * @param handle File handle returned by open() - * @param pbuf PBUF adjusted such that payload pointer points - * to the beginning of write data. In other words, - * TFTP headers are stripped off. - * @returns >= 0: Success; < 0: Error - */ - int (*write)(void* handle, struct pbuf* p); -}; - -err_t tftp_init(const struct tftp_context* ctx); -void tftp_cleanup(void); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_APPS_TFTP_SERVER_H */ diff --git a/core/c/include/lwip/arch.h b/core/c/include/lwip/arch.h deleted file mode 100755 index d281da7..0000000 --- a/core/c/include/lwip/arch.h +++ /dev/null @@ -1,393 +0,0 @@ -/** - * @file - * Support for different processor and compiler architectures - */ - -/* - * 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_HDR_ARCH_H -#define LWIP_HDR_ARCH_H - -#ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 1234 -#endif - -#ifndef BIG_ENDIAN -#define BIG_ENDIAN 4321 -#endif - -#include "arch/cc.h" - -/** - * @defgroup compiler_abstraction Compiler/platform abstraction - * @ingroup sys_layer - * All defines related to this section must not be placed in lwipopts.h, - * but in arch/cc.h! - * If the compiler does not provide memset() this file must include a - * definition of it, or include a file which defines it. - * These options cannot be \#defined in lwipopts.h since they are not options - * of lwIP itself, but options of the lwIP port to your system. - * @{ - */ - -/** Define the byte order of the system. - * Needed for conversion of network data to host byte order. - * Allowed values: LITTLE_ENDIAN and BIG_ENDIAN - */ -#ifndef BYTE_ORDER -#define BYTE_ORDER LITTLE_ENDIAN -#endif - -/** Define random number generator function of your system */ -#ifdef __DOXYGEN__ -#define LWIP_RAND() ((u32_t)rand()) -#endif - -/** Platform specific diagnostic output.\n - * Note the default implementation pulls in printf, which may - * in turn pull in a lot of standard libary code. In resource-constrained - * systems, this should be defined to something less resource-consuming. - */ -#ifndef LWIP_PLATFORM_DIAG -#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) -#include -#include -#endif - -/** Platform specific assertion handling.\n - * Note the default implementation pulls in printf, fflush and abort, which may - * in turn pull in a lot of standard libary code. In resource-constrained - * systems, this should be defined to something less resource-consuming. - */ -#ifndef LWIP_PLATFORM_ASSERT -#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ - x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) -#include -#include -#endif - -/** Define this to 1 in arch/cc.h of your port if you do not want to - * include stddef.h header to get size_t. You need to typedef size_t - * by yourself in this case. - */ -#ifndef LWIP_NO_STDDEF_H -#define LWIP_NO_STDDEF_H 0 -#endif - -#if !LWIP_NO_STDDEF_H -#include /* for size_t */ -#endif - -/** Define this to 1 in arch/cc.h of your port if your compiler does not provide - * the stdint.h header. You need to typedef the generic types listed in - * lwip/arch.h yourself in this case (u8_t, u16_t...). - */ -#ifndef LWIP_NO_STDINT_H -#define LWIP_NO_STDINT_H 0 -#endif - -/* Define generic types used in lwIP */ -#if !LWIP_NO_STDINT_H -#include -/* stdint.h is C99 which should also provide support for 64-bit integers */ -#if !defined(LWIP_HAVE_INT64) && defined(UINT64_MAX) -#define LWIP_HAVE_INT64 1 -#endif -typedef uint8_t u8_t; -typedef int8_t s8_t; -typedef uint16_t u16_t; -typedef int16_t s16_t; -typedef uint32_t u32_t; -typedef int32_t s32_t; -#if LWIP_HAVE_INT64 -typedef uint64_t u64_t; -typedef int64_t s64_t; -#endif -typedef uintptr_t mem_ptr_t; -#endif - -/** Define this to 1 in arch/cc.h of your port if your compiler does not provide - * the inttypes.h header. You need to define the format strings listed in - * lwip/arch.h yourself in this case (X8_F, U16_F...). - */ -#ifndef LWIP_NO_INTTYPES_H -#define LWIP_NO_INTTYPES_H 0 -#endif - -/* Define (sn)printf formatters for these lwIP types */ -#if !LWIP_NO_INTTYPES_H -#include -#ifndef X8_F -#define X8_F "02" PRIx8 -#endif -#ifndef U16_F -#define U16_F PRIu16 -#endif -#ifndef S16_F -#define S16_F PRId16 -#endif -#ifndef X16_F -#define X16_F PRIx16 -#endif -#ifndef U32_F -#define U32_F PRIu32 -#endif -#ifndef S32_F -#define S32_F PRId32 -#endif -#ifndef X32_F -#define X32_F PRIx32 -#endif -#ifndef SZT_F -#define SZT_F PRIuPTR -#endif -#endif - -/** Define this to 1 in arch/cc.h of your port if your compiler does not provide - * the limits.h header. You need to define the type limits yourself in this case - * (e.g. INT_MAX, SSIZE_MAX). - */ -#ifndef LWIP_NO_LIMITS_H -#define LWIP_NO_LIMITS_H 0 -#endif - -/* Include limits.h? */ -#if !LWIP_NO_LIMITS_H -#include -#endif - -/* Do we need to define ssize_t? This is a compatibility hack: - * Unfortunately, this type seems to be unavailable on some systems (even if - * sys/types or unistd.h are available). - * Being like that, we define it to 'int' if SSIZE_MAX is not defined. - */ -#ifdef SSIZE_MAX -/* If SSIZE_MAX is defined, unistd.h should provide the type as well */ -#ifndef LWIP_NO_UNISTD_H -#define LWIP_NO_UNISTD_H 0 -#endif -#if !LWIP_NO_UNISTD_H -#include -#endif -#else /* SSIZE_MAX */ -typedef int ssize_t; -#define SSIZE_MAX INT_MAX -#endif /* SSIZE_MAX */ - -/* some maximum values needed in lwip code */ -#define LWIP_UINT32_MAX 0xffffffff - -/** Define this to 1 in arch/cc.h of your port if your compiler does not provide - * the ctype.h header. If ctype.h is available, a few character functions - * are mapped to the appropriate functions (lwip_islower, lwip_isdigit...), if - * not, a private implementation is provided. - */ -#ifndef LWIP_NO_CTYPE_H -#define LWIP_NO_CTYPE_H 0 -#endif - -#if LWIP_NO_CTYPE_H -#define lwip_in_range(c, lo, up) ((u8_t)(c) >= (lo) && (u8_t)(c) <= (up)) -#define lwip_isdigit(c) lwip_in_range((c), '0', '9') -#define lwip_isxdigit(c) (lwip_isdigit(c) || lwip_in_range((c), 'a', 'f') || lwip_in_range((c), 'A', 'F')) -#define lwip_islower(c) lwip_in_range((c), 'a', 'z') -#define lwip_isspace(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || (c) == '\r' || (c) == '\t' || (c) == '\v') -#define lwip_isupper(c) lwip_in_range((c), 'A', 'Z') -#define lwip_tolower(c) (lwip_isupper(c) ? (c) - 'A' + 'a' : c) -#define lwip_toupper(c) (lwip_islower(c) ? (c) - 'a' + 'A' : c) -#else -#include -#define lwip_isdigit(c) isdigit((unsigned char)(c)) -#define lwip_isxdigit(c) isxdigit((unsigned char)(c)) -#define lwip_islower(c) islower((unsigned char)(c)) -#define lwip_isspace(c) isspace((unsigned char)(c)) -#define lwip_isupper(c) isupper((unsigned char)(c)) -#define lwip_tolower(c) tolower((unsigned char)(c)) -#define lwip_toupper(c) toupper((unsigned char)(c)) -#endif - -/** C++ const_cast(val) equivalent to remove constness from a value (GCC -Wcast-qual) */ -#ifndef LWIP_CONST_CAST -#define LWIP_CONST_CAST(target_type, val) ((target_type)((ptrdiff_t)val)) -#endif - -/** Get rid of alignment cast warnings (GCC -Wcast-align) */ -#ifndef LWIP_ALIGNMENT_CAST -#define LWIP_ALIGNMENT_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) -#endif - -/** Get rid of warnings related to pointer-to-numeric and vice-versa casts, - * e.g. "conversion from 'u8_t' to 'void *' of greater size" - */ -#ifndef LWIP_PTR_NUMERIC_CAST -#define LWIP_PTR_NUMERIC_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) -#endif - -/** Avoid warnings/errors related to implicitly casting away packed attributes by doing a explicit cast */ -#ifndef LWIP_PACKED_CAST -#define LWIP_PACKED_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) -#endif - -/** Allocates a memory buffer of specified size that is of sufficient size to align - * its start address using LWIP_MEM_ALIGN. - * You can declare your own version here e.g. to enforce alignment without adding - * trailing padding bytes (see LWIP_MEM_ALIGN_BUFFER) or your own section placement - * requirements.\n - * e.g. if you use gcc and need 32 bit alignment:\n - * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] \_\_attribute\_\_((aligned(4)))\n - * or more portable:\n - * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u32_t variable_name[(size + sizeof(u32_t) - 1) / sizeof(u32_t)] - */ -#ifndef LWIP_DECLARE_MEMORY_ALIGNED -#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] -#endif - -/** 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 - 1U) & ~(MEM_ALIGNMENT-1U)) -#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 - 1U)) -#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 -extern "C" { -#endif - -/** Packed structs support. - * Placed BEFORE declaration of a packed struct.\n - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n - * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. - */ -#ifndef PACK_STRUCT_BEGIN -#define PACK_STRUCT_BEGIN -#endif /* PACK_STRUCT_BEGIN */ - -/** Packed structs support. - * Placed AFTER declaration of a packed struct.\n - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n - * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. - */ -#ifndef PACK_STRUCT_END -#define PACK_STRUCT_END -#endif /* PACK_STRUCT_END */ - -/** Packed structs support. - * Placed between end of declaration of a packed struct and trailing semicolon.\n - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n - * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. - */ -#ifndef PACK_STRUCT_STRUCT -#if defined(__GNUC__) || defined(__clang__) -#define PACK_STRUCT_STRUCT __attribute__((packed)) -#else -#define PACK_STRUCT_STRUCT -#endif -#endif /* PACK_STRUCT_STRUCT */ - -/** Packed structs support. - * Wraps u32_t and u16_t members.\n - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n - * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. - */ -#ifndef PACK_STRUCT_FIELD -#define PACK_STRUCT_FIELD(x) x -#endif /* PACK_STRUCT_FIELD */ - -/** Packed structs support. - * Wraps u8_t members, where some compilers warn that packing is not necessary.\n - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n - * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. - */ -#ifndef PACK_STRUCT_FLD_8 -#define PACK_STRUCT_FLD_8(x) PACK_STRUCT_FIELD(x) -#endif /* PACK_STRUCT_FLD_8 */ - -/** Packed structs support. - * Wraps members that are packed structs themselves, where some compilers warn that packing is not necessary.\n - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n - * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. - */ -#ifndef PACK_STRUCT_FLD_S -#define PACK_STRUCT_FLD_S(x) PACK_STRUCT_FIELD(x) -#endif /* PACK_STRUCT_FLD_S */ - -/** PACK_STRUCT_USE_INCLUDES==1: Packed structs support using \#include files before and after struct to be packed.\n - * The file included BEFORE the struct is "arch/bpstruct.h".\n - * The file included AFTER the struct is "arch/epstruct.h".\n - * This can be used to implement struct packing on MS Visual C compilers, see - * the Win32 port in the lwIP contrib repository for reference. - * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n - * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. - */ -#ifdef __DOXYGEN__ -#define PACK_STRUCT_USE_INCLUDES -#endif - -/** Eliminates compiler warning about unused arguments (GCC -Wextra -Wunused). */ -#ifndef LWIP_UNUSED_ARG -#define LWIP_UNUSED_ARG(x) (void)x -#endif /* LWIP_UNUSED_ARG */ - -/** LWIP_PROVIDE_ERRNO==1: Let lwIP provide ERRNO values and the 'errno' variable. - * If this is disabled, cc.h must either define 'errno', include , - * define LWIP_ERRNO_STDINCLUDE to get included or - * define LWIP_ERRNO_INCLUDE to or equivalent. - */ -#if defined __DOXYGEN__ -#define LWIP_PROVIDE_ERRNO -#endif - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_ARCH_H */ diff --git a/core/c/include/lwip/autoip.h b/core/c/include/lwip/autoip.h deleted file mode 100755 index 5c6d13e..0000000 --- a/core/c/include/lwip/autoip.h +++ /dev/null @@ -1,99 +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. - * - */ - -#ifndef LWIP_HDR_AUTOIP_H -#define LWIP_HDR_AUTOIP_H - -#include "lwip/opt.h" - -#if LWIP_IPV4 && LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/netif.h" -/* #include "lwip/udp.h" */ -#include "lwip/etharp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** AutoIP Timing */ -#define AUTOIP_TMR_INTERVAL 100 -#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL) - -/** AutoIP state information per netif */ -struct autoip -{ - /** the currently selected, probed, announced or used LL IP-Address */ - ip4_addr_t llipaddr; - /** current AutoIP state machine state */ - u8_t state; - /** sent number of probes or announces, dependent on state */ - u8_t sent_num; - /** ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ - u16_t ttw; - /** ticks until a conflict can be solved by defending */ - u8_t lastconflict; - /** total number of probed/used Link Local IP-Addresses */ - u8_t tried_llipaddr; -}; - - -void autoip_set_struct(struct netif *netif, struct autoip *autoip); -/** Remove a struct autoip previously set to the netif using autoip_set_struct() */ -#define autoip_remove_struct(netif) do { (netif)->autoip = NULL; } while (0) -err_t autoip_start(struct netif *netif); -err_t autoip_stop(struct netif *netif); -void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); -void autoip_tmr(void); -void autoip_network_changed(struct netif *netif); -u8_t autoip_supplied_address(const struct netif *netif); - -/* for lwIP internal use by ip4.c */ -u8_t autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr); - -#define netif_autoip_data(netif) ((struct autoip*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP)) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV4 && LWIP_AUTOIP */ - -#endif /* LWIP_HDR_AUTOIP_H */ diff --git a/core/c/include/lwip/debug.h b/core/c/include/lwip/debug.h deleted file mode 100755 index 346ac47..0000000 --- a/core/c/include/lwip/debug.h +++ /dev/null @@ -1,161 +0,0 @@ -/** - * @file - * Debug messages infrastructure - */ - -/* - * 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_HDR_DEBUG_H -#define LWIP_HDR_DEBUG_H - -#include "lwip/arch.h" -#include "lwip/opt.h" - -/** - * @defgroup debugging_levels LWIP_DBG_MIN_LEVEL and LWIP_DBG_TYPES_ON values - * @ingroup lwip_opts_debugmsg - * @{ - */ - -/** @name Debug level (LWIP_DBG_MIN_LEVEL) - * @{ - */ -/** Debug level: ALL messages*/ -#define LWIP_DBG_LEVEL_ALL 0x00 -/** Debug level: Warnings. bad checksums, dropped packets, ... */ -#define LWIP_DBG_LEVEL_WARNING 0x01 -/** Debug level: Serious. memory allocation failures, ... */ -#define LWIP_DBG_LEVEL_SERIOUS 0x02 -/** Debug level: Severe */ -#define LWIP_DBG_LEVEL_SEVERE 0x03 -/** - * @} - */ - -#define LWIP_DBG_MASK_LEVEL 0x03 -/* compatibility define only */ -#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL - -/** @name Enable/disable debug messages completely (LWIP_DBG_TYPES_ON) - * @{ - */ -/** 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 -/** - * @} - */ - -/** @name Debug message types (LWIP_DBG_TYPES_ON) - * @{ - */ -/** 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 -/** - * @} - */ - -/** - * @} - */ - -/** - * @defgroup lwip_assertions Assertion handling - * @ingroup lwip_opts_debug - * @{ - */ -/** - * LWIP_NOASSERT: Disable LWIP_ASSERT checks: - * To disable assertions define LWIP_NOASSERT in arch/cc.h. - */ -#ifdef __DOXYGEN__ -#define LWIP_NOASSERT -#undef LWIP_NOASSERT -#endif -/** - * @} - */ - -#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 */ - -#ifndef LWIP_ERROR -#ifndef LWIP_NOASSERT -#define LWIP_PLATFORM_ERROR(message) LWIP_PLATFORM_ASSERT(message) -#elif defined LWIP_DEBUG -#define LWIP_PLATFORM_ERROR(message) LWIP_PLATFORM_DIAG((message)) -#else -#define LWIP_PLATFORM_ERROR(message) -#endif - -/* if "expression" isn't true, then print "message" and execute "handler" expression */ -#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ - LWIP_PLATFORM_ERROR(message); handler;}} while(0) -#endif /* LWIP_ERROR */ - -/** Enable debug message printing, but only if debug message type is enabled - * AND is of correct type AND is at least LWIP_DBG_LEVEL. - */ -#ifdef __DOXYGEN__ -#define LWIP_DEBUG -#undef LWIP_DEBUG -#endif - -#ifdef LWIP_DEBUG -#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_HDR_DEBUG_H */ diff --git a/core/c/include/lwip/def.h b/core/c/include/lwip/def.h deleted file mode 100755 index 10b5ac2..0000000 --- a/core/c/include/lwip/def.h +++ /dev/null @@ -1,152 +0,0 @@ -/** - * @file - * various utility macros - */ - -/* - * 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 - * - */ - -/** - * @defgroup perf Performance measurement - * @ingroup sys_layer - * All defines related to this section must not be placed in lwipopts.h, - * but in arch/perf.h! - * Measurement calls made throughout lwip, these can be defined to nothing. - * - PERF_START: start measuring something. - * - PERF_STOP(x): stop measuring something, and record the result. - */ - -#ifndef LWIP_HDR_DEF_H -#define LWIP_HDR_DEF_H - -/* arch.h might define NULL already */ -#include "lwip/arch.h" -#include "lwip/opt.h" -#if LWIP_PERF -#include "arch/perf.h" -#else /* LWIP_PERF */ -#define PERF_START /* null definition */ -#define PERF_STOP(x) /* null definition */ -#endif /* LWIP_PERF */ - -#ifdef __cplusplus -extern "C" { -#endif - -#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y)) -#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y)) - -/* Get the number of entries in an array ('x' must NOT be a pointer!) */ -#define LWIP_ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) - -/** Create u32_t value from bytes */ -#define LWIP_MAKEU32(a,b,c,d) (((u32_t)((a) & 0xff) << 24) | \ - ((u32_t)((b) & 0xff) << 16) | \ - ((u32_t)((c) & 0xff) << 8) | \ - (u32_t)((d) & 0xff)) - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#if BYTE_ORDER == BIG_ENDIAN -#define lwip_htons(x) ((u16_t)(x)) -#define lwip_ntohs(x) ((u16_t)(x)) -#define lwip_htonl(x) ((u32_t)(x)) -#define lwip_ntohl(x) ((u32_t)(x)) -#define PP_HTONS(x) ((u16_t)(x)) -#define PP_NTOHS(x) ((u16_t)(x)) -#define PP_HTONL(x) ((u32_t)(x)) -#define PP_NTOHL(x) ((u32_t)(x)) -#else /* BYTE_ORDER != BIG_ENDIAN */ -#ifndef lwip_htons -u16_t lwip_htons(u16_t x); -#endif -#define lwip_ntohs(x) lwip_htons(x) - -#ifndef lwip_htonl -u32_t lwip_htonl(u32_t x); -#endif -#define lwip_ntohl(x) lwip_htonl(x) - -/* 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) ((u16_t)((((x) & (u16_t)0x00ffU) << 8) | (((x) & (u16_t)0xff00U) >> 8))) -#define PP_NTOHS(x) PP_HTONS(x) -#define PP_HTONL(x) ((((x) & (u32_t)0x000000ffUL) << 24) | \ - (((x) & (u32_t)0x0000ff00UL) << 8) | \ - (((x) & (u32_t)0x00ff0000UL) >> 8) | \ - (((x) & (u32_t)0xff000000UL) >> 24)) -#define PP_NTOHL(x) PP_HTONL(x) -#endif /* BYTE_ORDER == BIG_ENDIAN */ - -/* Provide usual function names as macros for users, but this can be turned off */ -#ifndef LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS -#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 - -/* Functions that are not available as standard implementations. - * In cc.h, you can #define these to implementations available on - * your platform to save some code bytes if you use these functions - * in your application, too. - */ - -#ifndef lwip_itoa -/* This can be #defined to itoa() or snprintf(result, bufsize, "%d", number) depending on your platform */ -void lwip_itoa(char* result, size_t bufsize, int number); -#endif -#ifndef lwip_strnicmp -/* This can be #defined to strnicmp() or strncasecmp() depending on your platform */ -int lwip_strnicmp(const char* str1, const char* str2, size_t len); -#endif -#ifndef lwip_stricmp -/* This can be #defined to stricmp() or strcasecmp() depending on your platform */ -int lwip_stricmp(const char* str1, const char* str2); -#endif -#ifndef lwip_strnstr -/* This can be #defined to strnstr() depending on your platform */ -char* lwip_strnstr(const char* buffer, const char* token, size_t n); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_DEF_H */ diff --git a/core/c/include/lwip/dhcp.h b/core/c/include/lwip/dhcp.h deleted file mode 100755 index a965efd..0000000 --- a/core/c/include/lwip/dhcp.h +++ /dev/null @@ -1,139 +0,0 @@ -/** - * @file - * DHCP client API - */ - -/* - * 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 part of the lwIP TCP/IP stack. - * - * Author: Leon Woestenberg - * - */ -#ifndef LWIP_HDR_DHCP_H -#define LWIP_HDR_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_BOOT_FILE_LEN 128U - -/* AutoIP cooperation flags (struct dhcp.autoip_coop_state) */ -typedef enum { - DHCP_AUTOIP_COOP_STATE_OFF = 0, - DHCP_AUTOIP_COOP_STATE_ON = 1 -} dhcp_autoip_coop_state_enum_t; - -struct dhcp -{ - /** transaction identifier of last sent request */ - u32_t xid; - /** track PCB allocation state */ - u8_t pcb_allocated; - /** 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; - - 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 */ - u16_t t1_renew_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next renew try */ - u16_t t2_rebind_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next rebind try */ - u16_t lease_used; /* #ticks with period DHCP_COARSE_TIMER_SECS since last received DHCP ack */ - u16_t t0_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for lease time */ - ip_addr_t server_ip_addr; /* dhcp server address that offered this lease (ip_addr_t because passed to UDP) */ - ip4_addr_t offered_ip_addr; - ip4_addr_t offered_sn_mask; - ip4_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 87.5 of lease period) */ -#if LWIP_DHCP_BOOTP_FILE - ip4_addr_t offered_si_addr; - char boot_file_name[DHCP_BOOT_FILE_LEN]; -#endif /* LWIP_DHCP_BOOTPFILE */ -}; - - -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) netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, NULL) -void dhcp_cleanup(struct netif *netif); -err_t dhcp_start(struct netif *netif); -err_t dhcp_renew(struct netif *netif); -err_t dhcp_release(struct netif *netif); -void dhcp_stop(struct netif *netif); -void dhcp_release_and_stop(struct netif *netif); -void dhcp_inform(struct netif *netif); -void dhcp_network_changed(struct netif *netif); -#if DHCP_DOES_ARP_CHECK -void dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr); -#endif -u8_t dhcp_supplied_address(const struct netif *netif); -/* to be called every minute */ -void dhcp_coarse_tmr(void); -/* to be called every half second */ -void dhcp_fine_tmr(void); - -#if LWIP_DHCP_GET_NTP_SRV -/** This function must exist, in other to add offered NTP servers to - * the NTP (or SNTP) engine. - * See LWIP_DHCP_MAX_NTP_SERVERS */ -extern void dhcp_set_ntp_servers(u8_t num_ntp_servers, const ip4_addr_t* ntp_server_addrs); -#endif /* LWIP_DHCP_GET_NTP_SRV */ - -#define netif_dhcp_data(netif) ((struct dhcp*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP)) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_DHCP */ - -#endif /*LWIP_HDR_DHCP_H*/ diff --git a/core/c/include/lwip/dhcp6.h b/core/c/include/lwip/dhcp6.h deleted file mode 100755 index 61ca4c4..0000000 --- a/core/c/include/lwip/dhcp6.h +++ /dev/null @@ -1,104 +0,0 @@ -/** - * @file - * - * DHCPv6 client: IPv6 address autoconfiguration as per - * RFC 3315 (stateful DHCPv6) and - * RFC 3736 (stateless DHCPv6). - */ - -/* - * Copyright (c) 2018 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - */ - -#ifndef LWIP_HDR_IP6_DHCP6_H -#define LWIP_HDR_IP6_DHCP6_H - -#include "lwip/opt.h" - -#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/err.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** period (in milliseconds) of the application calling dhcp6_tmr() */ -#define DHCP6_TIMER_MSECS 500 - -struct dhcp6 -{ - /** transaction identifier of last sent request */ - u32_t xid; - /** track PCB allocation state */ - u8_t pcb_allocated; - /** current DHCPv6 state machine state */ - u8_t state; - /** retries of current request */ - u8_t tries; - /** if request config is triggered while another action is active, this keeps track of it */ - u8_t request_config_pending; - /** #ticks with period DHCP6_TIMER_MSECS for request timeout */ - u16_t request_timeout; -#if LWIP_IPV6_DHCP6_STATEFUL - /* @todo: add more members here to keep track of stateful DHCPv6 data, like lease times */ -#endif /* LWIP_IPV6_DHCP6_STATEFUL */ -}; - -void dhcp6_set_struct(struct netif *netif, struct dhcp6 *dhcp6); -/** Remove a struct dhcp6 previously set to the netif using dhcp6_set_struct() */ -#define dhcp6_remove_struct(netif) netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, NULL) -void dhcp6_cleanup(struct netif *netif); - -err_t dhcp6_enable_stateful(struct netif *netif); -err_t dhcp6_enable_stateless(struct netif *netif); -void dhcp6_disable(struct netif *netif); - -void dhcp6_tmr(void); - -void dhcp6_nd6_ra_trigger(struct netif *netif, u8_t managed_addr_config, u8_t other_config); - -#if LWIP_DHCP6_GET_NTP_SRV -/** This function must exist, in other to add offered NTP servers to - * the NTP (or SNTP) engine. - * See LWIP_DHCP6_MAX_NTP_SERVERS */ -extern void dhcp6_set_ntp_servers(u8_t num_ntp_servers, const ip_addr_t* ntp_server_addrs); -#endif /* LWIP_DHCP6_GET_NTP_SRV */ - -#define netif_dhcp6_data(netif) ((struct dhcp6*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6)) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6_DHCP6 */ - -#endif /* LWIP_HDR_IP6_DHCP6_H */ diff --git a/core/c/include/lwip/dns.h b/core/c/include/lwip/dns.h deleted file mode 100755 index eed6825..0000000 --- a/core/c/include/lwip/dns.h +++ /dev/null @@ -1,131 +0,0 @@ -/** - * @file - * DNS API - */ - -/** - * 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_HDR_DNS_H -#define LWIP_HDR_DNS_H - -#include "lwip/opt.h" - -#if LWIP_DNS - -#include "lwip/ip_addr.h" -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** DNS timer period */ -#define DNS_TMR_INTERVAL 1000 - -/* DNS resolve types: */ -#define LWIP_DNS_ADDRTYPE_IPV4 0 -#define LWIP_DNS_ADDRTYPE_IPV6 1 -#define LWIP_DNS_ADDRTYPE_IPV4_IPV6 2 /* try to resolve IPv4 first, try IPv6 if IPv4 fails only */ -#define LWIP_DNS_ADDRTYPE_IPV6_IPV4 3 /* try to resolve IPv6 first, try IPv4 if IPv6 fails only */ -#if LWIP_IPV4 && LWIP_IPV6 -#ifndef LWIP_DNS_ADDRTYPE_DEFAULT -#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV4_IPV6 -#endif -#elif LWIP_IPV4 -#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV4 -#else -#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV6 -#endif - -#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; -}; -#define DNS_LOCAL_HOSTLIST_ELEM(name, addr_init) {name, addr_init, NULL} -#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 */ - -#if LWIP_IPV4 -extern const ip_addr_t dns_mquery_v4group; -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 -extern const ip_addr_t dns_mquery_v6group; -#endif /* LWIP_IPV6 */ - -/** 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, const ip_addr_t *ipaddr, void *callback_arg); - -void dns_init(void); -void dns_tmr(void); -void dns_setserver(u8_t numdns, const ip_addr_t *dnsserver); -const 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); -err_t dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, - dns_found_callback found, void *callback_arg, - u8_t dns_addrtype); - - -#if DNS_LOCAL_HOSTLIST -size_t dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg); -err_t dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype); -#if 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_IS_DYNAMIC */ -#endif /* DNS_LOCAL_HOSTLIST */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_DNS */ - -#endif /* LWIP_HDR_DNS_H */ diff --git a/core/c/include/lwip/err.h b/core/c/include/lwip/err.h deleted file mode 100755 index 63c138a..0000000 --- a/core/c/include/lwip/err.h +++ /dev/null @@ -1,117 +0,0 @@ -/** - * @file - * lwIP Error codes - */ -/* - * 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_HDR_ERR_H -#define LWIP_HDR_ERR_H - -#include "lwip/opt.h" -#include "lwip/arch.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup infrastructure_errors Error codes - * @ingroup infrastructure - * @{ - */ - -/** Definitions for error constants. */ -typedef enum { -/** No error, everything 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, -/** Address in use. */ - ERR_USE = -8, -/** Already connecting. */ - ERR_ALREADY = -9, -/** Conn already established.*/ - ERR_ISCONN = -10, -/** Not connected. */ - ERR_CONN = -11, -/** Low-level netif error */ - ERR_IF = -12, - -/** Connection aborted. */ - ERR_ABRT = -13, -/** Connection reset. */ - ERR_RST = -14, -/** Connection closed. */ - ERR_CLSD = -15, -/** Illegal argument. */ - ERR_ARG = -16 -} err_enum_t; - -/** 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*/ - -/** - * @} - */ - -#ifdef LWIP_DEBUG -extern const char *lwip_strerr(err_t err); -#else -#define lwip_strerr(x) "" -#endif /* LWIP_DEBUG */ - -#if !NO_SYS -int err_to_errno(err_t err); -#endif /* !NO_SYS */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_ERR_H */ diff --git a/core/c/include/lwip/errno.h b/core/c/include/lwip/errno.h deleted file mode 100755 index eae5d6e..0000000 --- a/core/c/include/lwip/errno.h +++ /dev/null @@ -1,198 +0,0 @@ -/** - * @file - * Posix Errno defines - */ - -/* - * 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_HDR_ERRNO_H -#define LWIP_HDR_ERRNO_H - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#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 */ - -#ifndef errno -extern int errno; -#endif - -#else /* LWIP_PROVIDE_ERRNO */ - -/* Define LWIP_ERRNO_STDINCLUDE if you want to include here */ -#ifdef LWIP_ERRNO_STDINCLUDE -#include -#else /* LWIP_ERRNO_STDINCLUDE */ -/* Define LWIP_ERRNO_INCLUDE to an equivalent of to include the error defines here */ -#ifdef LWIP_ERRNO_INCLUDE -#include LWIP_ERRNO_INCLUDE -#endif /* LWIP_ERRNO_INCLUDE */ -#endif /* LWIP_ERRNO_STDINCLUDE */ - -#endif /* LWIP_PROVIDE_ERRNO */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_ERRNO_H */ diff --git a/core/c/include/lwip/etharp.h b/core/c/include/lwip/etharp.h deleted file mode 100755 index b018f07..0000000 --- a/core/c/include/lwip/etharp.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @file - * Ethernet output function - handles OUTGOING ethernet level traffic, implements - * ARP resolving. - * To be used in most low-level netif implementations - */ - -/* - * 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 LWIP_HDR_NETIF_ETHARP_H -#define LWIP_HDR_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/ip4_addr.h" -#include "lwip/netif.h" -#include "lwip/ip4.h" -#include "lwip/prot/ethernet.h" - -#if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/prot/etharp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** 1 seconds period */ -#define ARP_TMR_INTERVAL 1000 - -#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, no init needed. */ -void etharp_tmr(void); -ssize_t etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr, - struct eth_addr **eth_ret, const ip4_addr_t **ip_ret); -int etharp_get_entry(size_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth_addr **eth_ret); -err_t etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr); -err_t etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q); -err_t etharp_request(struct netif *netif, const ip4_addr_t *ipaddr); -/** For Ethernet network interfaces, we might want to send "gratuitous ARP"; - * this is an ARP packet sent by a node in order to spontaneously cause other - * nodes to update an entry in their ARP cache. - * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ -#define etharp_gratuitous(netif) etharp_request((netif), netif_ip4_addr(netif)) -void etharp_cleanup_netif(struct netif *netif); - -#if ETHARP_SUPPORT_STATIC_ENTRIES -err_t etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr); -err_t etharp_remove_static_entry(const ip4_addr_t *ipaddr); -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - -void etharp_input(struct pbuf *p, struct netif *netif); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV4 && LWIP_ARP */ -#endif /* LWIP_ARP || LWIP_ETHERNET */ - -#endif /* LWIP_HDR_NETIF_ETHARP_H */ diff --git a/core/c/include/lwip/ethip6.h b/core/c/include/lwip/ethip6.h deleted file mode 100755 index f393c9c..0000000 --- a/core/c/include/lwip/ethip6.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file - * - * Ethernet output for IPv6. Uses ND tables for link-layer addressing. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#ifndef LWIP_HDR_ETHIP6_H -#define LWIP_HDR_ETHIP6_H - -#include "lwip/opt.h" - -#if LWIP_IPV6 && LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/pbuf.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/netif.h" - - -#ifdef __cplusplus -extern "C" { -#endif - - -err_t ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6 && LWIP_ETHERNET */ - -#endif /* LWIP_HDR_ETHIP6_H */ diff --git a/core/c/include/lwip/icmp.h b/core/c/include/lwip/icmp.h deleted file mode 100755 index d0d67b6..0000000 --- a/core/c/include/lwip/icmp.h +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @file - * ICMP API - */ - -/* - * 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_HDR_ICMP_H -#define LWIP_HDR_ICMP_H - -#include "lwip/opt.h" -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/prot/icmp.h" - -#if LWIP_IPV6 && LWIP_ICMP6 -#include "lwip/icmp6.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** ICMP destination unreachable codes */ -enum icmp_dur_type { - /** net unreachable */ - ICMP_DUR_NET = 0, - /** host unreachable */ - ICMP_DUR_HOST = 1, - /** protocol unreachable */ - ICMP_DUR_PROTO = 2, - /** port unreachable */ - ICMP_DUR_PORT = 3, - /** fragmentation needed and DF set */ - ICMP_DUR_FRAG = 4, - /** source route failed */ - ICMP_DUR_SR = 5 -}; - -/** ICMP time exceeded codes */ -enum icmp_te_type { - /** time to live exceeded in transit */ - ICMP_TE_TTL = 0, - /** fragment reassembly time exceeded */ - ICMP_TE_FRAG = 1 -}; - -#if LWIP_IPV4 && LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ - -void icmp_input(struct pbuf *p, struct netif *inp); -void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t); -void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); - -#endif /* LWIP_IPV4 && LWIP_ICMP */ - -#if LWIP_IPV4 && LWIP_IPV6 -#if LWIP_ICMP && LWIP_ICMP6 -#define icmp_port_unreach(isipv6, pbuf) ((isipv6) ? \ - icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) : \ - icmp_dest_unreach(pbuf, ICMP_DUR_PORT)) -#elif LWIP_ICMP -#define icmp_port_unreach(isipv6, pbuf) do{ if(!(isipv6)) { icmp_dest_unreach(pbuf, ICMP_DUR_PORT);}}while(0) -#elif LWIP_ICMP6 -#define icmp_port_unreach(isipv6, pbuf) do{ if(isipv6) { icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT);}}while(0) -#else -#define icmp_port_unreach(isipv6, pbuf) -#endif -#elif LWIP_IPV6 && LWIP_ICMP6 -#define icmp_port_unreach(isipv6, pbuf) icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) -#elif LWIP_IPV4 && LWIP_ICMP -#define icmp_port_unreach(isipv6, pbuf) icmp_dest_unreach(pbuf, ICMP_DUR_PORT) -#else /* (LWIP_IPV6 && LWIP_ICMP6) || (LWIP_IPV4 && LWIP_ICMP) */ -#define icmp_port_unreach(isipv6, pbuf) -#endif /* (LWIP_IPV6 && LWIP_ICMP6) || (LWIP_IPV4 && LWIP_ICMP) LWIP_IPV4*/ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_ICMP_H */ diff --git a/core/c/include/lwip/icmp6.h b/core/c/include/lwip/icmp6.h deleted file mode 100755 index cb383d9..0000000 --- a/core/c/include/lwip/icmp6.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file - * - * IPv6 version of ICMP, as per RFC 4443. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ -#ifndef LWIP_HDR_ICMP6_H -#define LWIP_HDR_ICMP6_H - -#include "lwip/opt.h" -#include "lwip/pbuf.h" -#include "lwip/ip6_addr.h" -#include "lwip/netif.h" -#include "lwip/prot/icmp6.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -void icmp6_input(struct pbuf *p, struct netif *inp); -void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c); -void icmp6_packet_too_big(struct pbuf *p, u32_t mtu); -void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c); -void icmp6_time_exceeded_with_addrs(struct pbuf *p, enum icmp6_te_code c, - const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr); -void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, const void *pointer); - -#endif /* LWIP_ICMP6 && LWIP_IPV6 */ - - -#ifdef __cplusplus -} -#endif - - -#endif /* LWIP_HDR_ICMP6_H */ diff --git a/core/c/include/lwip/if_api.h b/core/c/include/lwip/if_api.h deleted file mode 100755 index d8261f7..0000000 --- a/core/c/include/lwip/if_api.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file - * Interface Identification APIs from: - * RFC 3493: Basic Socket Interface Extensions for IPv6 - * Section 4: Interface Identification - */ - -/* - * Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. - * 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: Joel Cunningham - * - */ -#ifndef LWIP_HDR_IF_H -#define LWIP_HDR_IF_H - -#include "lwip/opt.h" - -#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define IF_NAMESIZE NETIF_NAMESIZE - -char * lwip_if_indextoname(unsigned int ifindex, char *ifname); -unsigned int lwip_if_nametoindex(const char *ifname); - -#if LWIP_COMPAT_SOCKETS -#define if_indextoname(ifindex, ifname) lwip_if_indextoname(ifindex,ifname) -#define if_nametoindex(ifname) lwip_if_nametoindex(ifname) -#endif /* LWIP_COMPAT_SOCKETS */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SOCKET */ - -#endif /* LWIP_HDR_IF_H */ diff --git a/core/c/include/lwip/igmp.h b/core/c/include/lwip/igmp.h deleted file mode 100755 index ca52a2d..0000000 --- a/core/c/include/lwip/igmp.h +++ /dev/null @@ -1,115 +0,0 @@ -/** - * @file - * IGMP API - */ - -/* - * 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_HDR_IGMP_H -#define LWIP_HDR_IGMP_H - -#include "lwip/opt.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/pbuf.h" - -#if LWIP_IPV4 && 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) - -/* Compatibility defines (don't use for new code) */ -#define IGMP_DEL_MAC_FILTER NETIF_DEL_MAC_FILTER -#define IGMP_ADD_MAC_FILTER NETIF_ADD_MAC_FILTER - -/** - * 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; - /** multicast address */ - ip4_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); -err_t igmp_start(struct netif *netif); -err_t igmp_stop(struct netif *netif); -void igmp_report_groups(struct netif *netif); -struct igmp_group *igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr); -void igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest); -err_t igmp_joingroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr); -err_t igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr); -err_t igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr); -err_t igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr); -void igmp_tmr(void); - -/** @ingroup igmp - * Get list head of IGMP groups for netif. - * Note: The allsystems group IP is contained in the list as first entry. - * @see @ref netif_set_igmp_mac_filter() - */ -#define netif_igmp_data(netif) ((struct igmp_group *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP)) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV4 && LWIP_IGMP */ - -#endif /* LWIP_HDR_IGMP_H */ diff --git a/core/c/include/lwip/inet.h b/core/c/include/lwip/inet.h deleted file mode 100755 index 36f6ec7..0000000 --- a/core/c/include/lwip/inet.h +++ /dev/null @@ -1,169 +0,0 @@ -/** - * @file - * This file (together with sockets.h) aims to provide structs and functions from - * - arpa/inet.h - * - netinet/in.h - * - */ - -/* - * 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_HDR_INET_H -#define LWIP_HDR_INET_H - -#include "lwip/opt.h" -#include "lwip/def.h" -#include "lwip/ip_addr.h" -#include "lwip/ip6_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED - to prevent this code from redefining it. */ -#if !defined(in_addr_t) && !defined(IN_ADDR_T_DEFINED) -typedef u32_t in_addr_t; -#endif - -struct in_addr { - in_addr_t s_addr; -}; - -struct in6_addr { - union { - u32_t u32_addr[4]; - u8_t u8_addr[16]; - } un; -#define s6_addr un.u8_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 - -/** This macro can be used to initialize a variable of type struct in6_addr - to the IPv6 wildcard address. */ -#define IN6ADDR_ANY_INIT {{{0,0,0,0}}} -/** This macro can be used to initialize a variable of type struct in6_addr - to the IPv6 loopback address. */ -#define IN6ADDR_LOOPBACK_INIT {{{0,0,0,PP_HTONL(1)}}} -/** This variable is initialized by the system to contain the wildcard IPv6 address. */ -extern const struct in6_addr in6addr_any; - -/* Definitions of the bits in an (IPv4) 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 - - -#ifndef INET_ADDRSTRLEN -#define INET_ADDRSTRLEN IP4ADDR_STRLEN_MAX -#endif -#if LWIP_IPV6 -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN IP6ADDR_STRLEN_MAX -#endif -#endif - -#if LWIP_IPV4 - -#define inet_addr_from_ip4addr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) -#define inet_addr_to_ip4addr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) - -/* directly map this to the lwip internal functions */ -#define inet_addr(cp) ipaddr_addr(cp) -#define inet_aton(cp, addr) ip4addr_aton(cp, (ip4_addr_t*)addr) -#define inet_ntoa(addr) ip4addr_ntoa((const ip4_addr_t*)&(addr)) -#define inet_ntoa_r(addr, buf, buflen) ip4addr_ntoa_r((const ip4_addr_t*)&(addr), buf, buflen) - -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6 -#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->un.u32_addr[0] = (source_ip6addr)->addr[0]; \ - (target_in6addr)->un.u32_addr[1] = (source_ip6addr)->addr[1]; \ - (target_in6addr)->un.u32_addr[2] = (source_ip6addr)->addr[2]; \ - (target_in6addr)->un.u32_addr[3] = (source_ip6addr)->addr[3];} -#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->un.u32_addr[0]; \ - (target_ip6addr)->addr[1] = (source_in6addr)->un.u32_addr[1]; \ - (target_ip6addr)->addr[2] = (source_in6addr)->un.u32_addr[2]; \ - (target_ip6addr)->addr[3] = (source_in6addr)->un.u32_addr[3]; \ - ip6_addr_clear_zone(target_ip6addr);} - -/* directly map this to the lwip internal functions */ -#define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr) -#define inet6_ntoa(addr) ip6addr_ntoa((const ip6_addr_t*)&(addr)) -#define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((const ip6_addr_t*)&(addr), buf, buflen) - -#endif /* LWIP_IPV6 */ - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_INET_H */ diff --git a/core/c/include/lwip/inet_chksum.h b/core/c/include/lwip/inet_chksum.h deleted file mode 100755 index 46ec2ae..0000000 --- a/core/c/include/lwip/inet_chksum.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @file - * IP checksum calculation 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 - * - */ -#ifndef LWIP_HDR_INET_CHKSUM_H -#define LWIP_HDR_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 lwip_htons() for little-endian */ -#ifndef SWAP_BYTES_IN_WORD -#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8) -#endif /* SWAP_BYTES_IN_WORD */ - -/** Split an u32_t in two u16_ts and add them up */ -#ifndef FOLD_U32T -#define FOLD_U32T(u) ((u32_t)(((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 */ -# else /* LWIP_CHKSUM_COPY */ -# define LWIP_CHKSUM_COPY_ALGORITHM 0 -# 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(const void *dataptr, u16_t len); -u16_t inet_chksum_pbuf(struct pbuf *p); -#if LWIP_CHKSUM_COPY_ALGORITHM -u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len); -#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ - -#if LWIP_IPV4 -u16_t inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, - const ip4_addr_t *src, const ip4_addr_t *dest); -u16_t inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, - u16_t proto_len, u16_t chksum_len, const ip4_addr_t *src, const ip4_addr_t *dest); -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6 -u16_t ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, - const ip6_addr_t *src, const ip6_addr_t *dest); -u16_t ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, - u16_t chksum_len, const ip6_addr_t *src, const ip6_addr_t *dest); -#endif /* LWIP_IPV6 */ - - -u16_t ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, - const ip_addr_t *src, const ip_addr_t *dest); -u16_t ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, - u16_t chksum_len, const ip_addr_t *src, const ip_addr_t *dest); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_INET_H */ - diff --git a/core/c/include/lwip/init.h b/core/c/include/lwip/init.h deleted file mode 100755 index 48c256b..0000000 --- a/core/c/include/lwip/init.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @file - * lwIP initialization API - */ - -/* - * 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_HDR_INIT_H -#define LWIP_HDR_INIT_H - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup lwip_version Version - * @ingroup lwip - * @{ - */ - -/** X.x.x: Major version of the stack */ -#define LWIP_VERSION_MAJOR 2 -/** x.X.x: Minor version of the stack */ -#define LWIP_VERSION_MINOR 1 -/** x.x.X: Revision of the stack */ -#define LWIP_VERSION_REVISION 2 -/** For release candidates, this is set to 1..254 - * For official releases, this is set to 255 (LWIP_RC_RELEASE) - * For development versions (Git), this is set to 0 (LWIP_RC_DEVELOPMENT) */ -#define LWIP_VERSION_RC LWIP_RC_RELEASE - -/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ -#define LWIP_RC_RELEASE 255 -/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for Git versions */ -#define LWIP_RC_DEVELOPMENT 0 - -#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)) - -/* Some helper defines to get a version string */ -#define LWIP_VERSTR2(x) #x -#define LWIP_VERSTR(x) LWIP_VERSTR2(x) -#if LWIP_VERSION_IS_RELEASE -#define LWIP_VERSION_STRING_SUFFIX "" -#elif LWIP_VERSION_IS_DEVELOPMENT -#define LWIP_VERSION_STRING_SUFFIX "d" -#else -#define LWIP_VERSION_STRING_SUFFIX "rc" LWIP_VERSTR(LWIP_VERSION_RC) -#endif - -/** Provides the version of the stack */ -#define LWIP_VERSION ((LWIP_VERSION_MAJOR) << 24 | (LWIP_VERSION_MINOR) << 16 | \ - (LWIP_VERSION_REVISION) << 8 | (LWIP_VERSION_RC)) -/** Provides the version of the stack as string */ -#define LWIP_VERSION_STRING LWIP_VERSTR(LWIP_VERSION_MAJOR) "." LWIP_VERSTR(LWIP_VERSION_MINOR) "." LWIP_VERSTR(LWIP_VERSION_REVISION) LWIP_VERSION_STRING_SUFFIX - -/** - * @} - */ - -/* Modules initialization */ -void lwip_init(void); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_INIT_H */ diff --git a/core/c/include/lwip/init.h.cmake.in b/core/c/include/lwip/init.h.cmake.in deleted file mode 100755 index d7c017e..0000000 --- a/core/c/include/lwip/init.h.cmake.in +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @file - * lwIP initialization API - */ - -/* - * 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_HDR_INIT_H -#define LWIP_HDR_INIT_H - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup lwip_version Version - * @ingroup lwip - * @{ - */ - -/** X.x.x: Major version of the stack */ -#define LWIP_VERSION_MAJOR ${LWIP_VERSION_MAJOR} -/** x.X.x: Minor version of the stack */ -#define LWIP_VERSION_MINOR ${LWIP_VERSION_MINOR} -/** x.x.X: Revision of the stack */ -#define LWIP_VERSION_REVISION ${LWIP_VERSION_REVISION} -/** For release candidates, this is set to 1..254 - * For official releases, this is set to 255 (LWIP_RC_RELEASE) - * For development versions (Git), this is set to 0 (LWIP_RC_DEVELOPMENT) */ -#define LWIP_VERSION_RC ${LWIP_VERSION_RC} - -/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ -#define LWIP_RC_RELEASE 255 -/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for Git versions */ -#define LWIP_RC_DEVELOPMENT 0 - -#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)) - -/* Some helper defines to get a version string */ -#define LWIP_VERSTR2(x) #x -#define LWIP_VERSTR(x) LWIP_VERSTR2(x) -#if LWIP_VERSION_IS_RELEASE -#define LWIP_VERSION_STRING_SUFFIX "" -#elif LWIP_VERSION_IS_DEVELOPMENT -#define LWIP_VERSION_STRING_SUFFIX "d" -#else -#define LWIP_VERSION_STRING_SUFFIX "rc" LWIP_VERSTR(LWIP_VERSION_RC) -#endif - -/** Provides the version of the stack */ -#define LWIP_VERSION ((LWIP_VERSION_MAJOR) << 24 | (LWIP_VERSION_MINOR) << 16 | \ - (LWIP_VERSION_REVISION) << 8 | (LWIP_VERSION_RC)) -/** Provides the version of the stack as string */ -#define LWIP_VERSION_STRING LWIP_VERSTR(LWIP_VERSION_MAJOR) "." LWIP_VERSTR(LWIP_VERSION_MINOR) "." LWIP_VERSTR(LWIP_VERSION_REVISION) LWIP_VERSION_STRING_SUFFIX - -/** - * @} - */ - -/* Modules initialization */ -void lwip_init(void); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_INIT_H */ diff --git a/core/c/include/lwip/ip.h b/core/c/include/lwip/ip.h deleted file mode 100755 index 28889d5..0000000 --- a/core/c/include/lwip/ip.h +++ /dev/null @@ -1,330 +0,0 @@ -/** - * @file - * IP API - */ - -/* - * 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_HDR_IP_H -#define LWIP_HDR_IP_H - -#include "lwip/opt.h" - -#include "lwip/def.h" -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" -#include "lwip/err.h" -#include "lwip/netif.h" -#include "lwip/ip4.h" -#include "lwip/ip6.h" -#include "lwip/prot/ip.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is passed as the destination address to ip_output_if (not - to ip_output), meaning that an IP header already is constructed - in the pbuf. This is used when TCP retransmits. */ -#define LWIP_IP_HDRINCL NULL - -/** 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 */ -#ifndef LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX -#define LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p) LWIP_ASSERT("p->ref == 1", (p)->ref == 1) -#endif - -#if LWIP_NETIF_USE_HINTS -#define IP_PCB_NETIFHINT ;struct netif_hint netif_hints -#else /* LWIP_NETIF_USE_HINTS */ -#define IP_PCB_NETIFHINT -#endif /* LWIP_NETIF_USE_HINTS */ - -/** 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; \ - /* Bound netif index */ \ - u8_t netif_idx; \ - /* 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_NETIFHINT - -struct ip_pcb { - /* Common members of all PCB types */ - IP_PCB; -}; - -/* - * Option flags per-socket. These are the same like SO_XXX in sockets.h - */ -#define SOF_REUSEADDR 0x04U /* allow local address reuse */ -#define SOF_KEEPALIVE 0x08U /* keep connections alive */ -#define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ - -/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ -#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE) - -/** Global variables of this module, kept in a struct for efficient access using base+index. */ -struct ip_globals -{ - /** The interface that accepted the packet for the current callback invocation. */ - struct netif *current_netif; - /** The interface that received the packet for the current callback invocation. */ - struct netif *current_input_netif; -#if LWIP_IPV4 - /** Header of the input packet currently being processed. */ - const struct ip_hdr *current_ip4_header; -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 - /** Header of the input IPv6 packet currently being processed. */ - struct ip6_hdr *current_ip6_header; -#endif /* LWIP_IPV6 */ - /** Total header length of current_ip4/6_header (i.e. after this, the UDP/TCP header starts) */ - u16_t current_ip_header_tot_len; - /** Source IP address of current_header */ - ip_addr_t current_iphdr_src; - /** Destination IP address of current_header */ - ip_addr_t current_iphdr_dest; -}; -extern struct ip_globals ip_data; - - -/** Get the interface that accepted the current packet. - * This may or may not be the receiving netif, depending on your netif/network setup. - * This function must only be called from a receive callback (udp_recv, - * raw_recv, tcp_accept). It will return NULL otherwise. */ -#define ip_current_netif() (ip_data.current_netif) -/** Get the 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_input_netif() (ip_data.current_input_netif) -/** Total header length of ip(6)_current_header() (i.e. after this, the UDP/TCP header starts) */ -#define ip_current_header_tot_len() (ip_data.current_ip_header_tot_len) -/** Source IP address of current_header */ -#define ip_current_src_addr() (&ip_data.current_iphdr_src) -/** Destination IP address of current_header */ -#define ip_current_dest_addr() (&ip_data.current_iphdr_dest) - -#if LWIP_IPV4 && LWIP_IPV6 -/** Get the IPv4 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 ip4_current_header() ip_data.current_ip4_header -/** Get the IPv6 header of the current packet. - * This function must only be called from a receive callback (udp_recv, - * raw_recv, tcp_accept). It will return NULL otherwise. */ -#define ip6_current_header() ((const struct ip6_hdr*)(ip_data.current_ip6_header)) -/** Returns TRUE if the current IP input packet is IPv6, FALSE if it is IPv4 */ -#define ip_current_is_v6() (ip6_current_header() != NULL) -/** Source IPv6 address of current_header */ -#define ip6_current_src_addr() (ip_2_ip6(&ip_data.current_iphdr_src)) -/** Destination IPv6 address of current_header */ -#define ip6_current_dest_addr() (ip_2_ip6(&ip_data.current_iphdr_dest)) -/** Get the transport layer protocol */ -#define ip_current_header_proto() (ip_current_is_v6() ? \ - IP6H_NEXTH(ip6_current_header()) :\ - IPH_PROTO(ip4_current_header())) -/** Get the transport layer header */ -#define ip_next_header_ptr() ((const void*)((ip_current_is_v6() ? \ - (const u8_t*)ip6_current_header() : (const u8_t*)ip4_current_header()) + ip_current_header_tot_len())) - -/** Source IP4 address of current_header */ -#define ip4_current_src_addr() (ip_2_ip4(&ip_data.current_iphdr_src)) -/** Destination IP4 address of current_header */ -#define ip4_current_dest_addr() (ip_2_ip4(&ip_data.current_iphdr_dest)) - -#elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */ - -/** Get the IPv4 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 ip4_current_header() ip_data.current_ip4_header -/** Always returns FALSE when only supporting IPv4 only */ -#define ip_current_is_v6() 0 -/** Get the transport layer protocol */ -#define ip_current_header_proto() IPH_PROTO(ip4_current_header()) -/** Get the transport layer header */ -#define ip_next_header_ptr() ((const void*)((const u8_t*)ip4_current_header() + ip_current_header_tot_len())) -/** Source IP4 address of current_header */ -#define ip4_current_src_addr() (&ip_data.current_iphdr_src) -/** Destination IP4 address of current_header */ -#define ip4_current_dest_addr() (&ip_data.current_iphdr_dest) - -#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ - -/** Get the IPv6 header of the current packet. - * This function must only be called from a receive callback (udp_recv, - * raw_recv, tcp_accept). It will return NULL otherwise. */ -#define ip6_current_header() ((const struct ip6_hdr*)(ip_data.current_ip6_header)) -/** Always returns TRUE when only supporting IPv6 only */ -#define ip_current_is_v6() 1 -/** Get the transport layer protocol */ -#define ip_current_header_proto() IP6H_NEXTH(ip6_current_header()) -/** Get the transport layer header */ -#define ip_next_header_ptr() ((const void*)(((const u8_t*)ip6_current_header()) + ip_current_header_tot_len())) -/** Source IP6 address of current_header */ -#define ip6_current_src_addr() (&ip_data.current_iphdr_src) -/** Destination IP6 address of current_header */ -#define ip6_current_dest_addr() (&ip_data.current_iphdr_dest) - -#endif /* LWIP_IPV6 */ - -/** Union source address of current_header */ -#define ip_current_src_addr() (&ip_data.current_iphdr_src) -/** Union destination address of current_header */ -#define ip_current_dest_addr() (&ip_data.current_iphdr_dest) - -/** Gets an IP pcb option (SOF_* flags) */ -#define ip_get_option(pcb, opt) ((pcb)->so_options & (opt)) -/** Sets an IP pcb option (SOF_* flags) */ -#define ip_set_option(pcb, opt) ((pcb)->so_options = (u8_t)((pcb)->so_options | (opt))) -/** Resets an IP pcb option (SOF_* flags) */ -#define ip_reset_option(pcb, opt) ((pcb)->so_options = (u8_t)((pcb)->so_options & ~(opt))) - -#if LWIP_IPV4 && LWIP_IPV6 -/** - * @ingroup ip - * Output IP packet, netif is selected by source address - */ -#define ip_output(p, src, dest, ttl, tos, proto) \ - (IP_IS_V6(dest) ? \ - ip6_output(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto) : \ - ip4_output(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto)) -/** - * @ingroup ip - * Output IP packet to specified interface - */ -#define ip_output_if(p, src, dest, ttl, tos, proto, netif) \ - (IP_IS_V6(dest) ? \ - ip6_output_if(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ - ip4_output_if(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, netif)) -/** - * @ingroup ip - * Output IP packet to interface specifying source address - */ -#define ip_output_if_src(p, src, dest, ttl, tos, proto, netif) \ - (IP_IS_V6(dest) ? \ - ip6_output_if_src(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ - ip4_output_if_src(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, netif)) -/** Output IP packet that already includes an IP header. */ -#define ip_output_if_hdrincl(p, src, dest, netif) \ - (IP_IS_V6(dest) ? \ - ip6_output_if(p, ip_2_ip6(src), LWIP_IP_HDRINCL, 0, 0, 0, netif) : \ - ip4_output_if(p, ip_2_ip4(src), LWIP_IP_HDRINCL, 0, 0, 0, netif)) -/** Output IP packet with netif_hint */ -#define ip_output_hinted(p, src, dest, ttl, tos, proto, netif_hint) \ - (IP_IS_V6(dest) ? \ - ip6_output_hinted(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif_hint) : \ - ip4_output_hinted(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, netif_hint)) -/** - * @ingroup ip - * Get netif for address combination. See \ref ip6_route and \ref ip4_route - */ -#define ip_route(src, dest) \ - (IP_IS_V6(dest) ? \ - ip6_route(ip_2_ip6(src), ip_2_ip6(dest)) : \ - ip4_route_src(ip_2_ip4(src), ip_2_ip4(dest))) -/** - * @ingroup ip - * Get netif for IP. - */ -#define ip_netif_get_local_ip(netif, dest) (IP_IS_V6(dest) ? \ - ip6_netif_get_local_ip(netif, ip_2_ip6(dest)) : \ - ip4_netif_get_local_ip(netif)) -#define ip_debug_print(is_ipv6, p) ((is_ipv6) ? ip6_debug_print(p) : ip4_debug_print(p)) - -err_t ip_input(struct pbuf *p, struct netif *inp); - -#elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */ - -#define ip_output(p, src, dest, ttl, tos, proto) \ - ip4_output(p, src, dest, ttl, tos, proto) -#define ip_output_if(p, src, dest, ttl, tos, proto, netif) \ - ip4_output_if(p, src, dest, ttl, tos, proto, netif) -#define ip_output_if_src(p, src, dest, ttl, tos, proto, netif) \ - ip4_output_if_src(p, src, dest, ttl, tos, proto, netif) -#define ip_output_hinted(p, src, dest, ttl, tos, proto, netif_hint) \ - ip4_output_hinted(p, src, dest, ttl, tos, proto, netif_hint) -#define ip_output_if_hdrincl(p, src, dest, netif) \ - ip4_output_if(p, src, LWIP_IP_HDRINCL, 0, 0, 0, netif) -#define ip_route(src, dest) \ - ip4_route_src(src, dest) -#define ip_netif_get_local_ip(netif, dest) \ - ip4_netif_get_local_ip(netif) -#define ip_debug_print(is_ipv6, p) ip4_debug_print(p) - -#define ip_input ip4_input - -#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ - -#define ip_output(p, src, dest, ttl, tos, proto) \ - ip6_output(p, src, dest, ttl, tos, proto) -#define ip_output_if(p, src, dest, ttl, tos, proto, netif) \ - ip6_output_if(p, src, dest, ttl, tos, proto, netif) -#define ip_output_if_src(p, src, dest, ttl, tos, proto, netif) \ - ip6_output_if_src(p, src, dest, ttl, tos, proto, netif) -#define ip_output_hinted(p, src, dest, ttl, tos, proto, netif_hint) \ - ip6_output_hinted(p, src, dest, ttl, tos, proto, netif_hint) -#define ip_output_if_hdrincl(p, src, dest, netif) \ - ip6_output_if(p, src, LWIP_IP_HDRINCL, 0, 0, 0, netif) -#define ip_route(src, dest) \ - ip6_route(src, dest) -#define ip_netif_get_local_ip(netif, dest) \ - ip6_netif_get_local_ip(netif, dest) -#define ip_debug_print(is_ipv6, p) ip6_debug_print(p) - -#define ip_input ip6_input - -#endif /* LWIP_IPV6 */ - -#define ip_route_get_local_ip(src, dest, netif, ipaddr) do { \ - (netif) = ip_route(src, dest); \ - (ipaddr) = ip_netif_get_local_ip(netif, dest); \ -}while(0) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_IP_H */ - - diff --git a/core/c/include/lwip/ip4.h b/core/c/include/lwip/ip4.h deleted file mode 100755 index 6409c4b..0000000 --- a/core/c/include/lwip/ip4.h +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @file - * IPv4 API - */ - -/* - * 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_HDR_IP4_H -#define LWIP_HDR_IP4_H - -#include "lwip/opt.h" - -#if LWIP_IPV4 - -#include "lwip/def.h" -#include "lwip/pbuf.h" -#include "lwip/ip4_addr.h" -#include "lwip/err.h" -#include "lwip/netif.h" -#include "lwip/prot/ip4.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef LWIP_HOOK_IP4_ROUTE_SRC -#define LWIP_IPV4_SRC_ROUTING 1 -#else -#define LWIP_IPV4_SRC_ROUTING 0 -#endif - -/** Currently, the function ip_output_if_opt() is only used with IGMP */ -#define IP_OPTIONS_SEND (LWIP_IPV4 && LWIP_IGMP) - -#define ip_init() /* Compatibility define, no init needed. */ -struct netif *ip4_route(const ip4_addr_t *dest); -#if LWIP_IPV4_SRC_ROUTING -struct netif *ip4_route_src(const ip4_addr_t *src, const ip4_addr_t *dest); -#else /* LWIP_IPV4_SRC_ROUTING */ -#define ip4_route_src(src, dest) ip4_route(dest) -#endif /* LWIP_IPV4_SRC_ROUTING */ -err_t ip4_input(struct pbuf *p, struct netif *inp); -err_t ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto); -err_t ip4_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); -err_t ip4_output_if_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); -#if LWIP_NETIF_USE_HINTS -err_t ip4_output_hinted(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, struct netif_hint *netif_hint); -#endif /* LWIP_NETIF_USE_HINTS */ -#if IP_OPTIONS_SEND -err_t ip4_output_if_opt(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, - u16_t optlen); -err_t ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_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 */ - -#if LWIP_MULTICAST_TX_OPTIONS -void ip4_set_default_multicast_netif(struct netif* default_multicast_netif); -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - -#define ip4_netif_get_local_ip(netif) (((netif) != NULL) ? netif_ip_addr4(netif) : NULL) - -#if IP_DEBUG -void ip4_debug_print(struct pbuf *p); -#else -#define ip4_debug_print(p) -#endif /* IP_DEBUG */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV4 */ - -#endif /* LWIP_HDR_IP_H */ - - diff --git a/core/c/include/lwip/ip4_addr.h b/core/c/include/lwip/ip4_addr.h deleted file mode 100755 index 9990756..0000000 --- a/core/c/include/lwip/ip4_addr.h +++ /dev/null @@ -1,216 +0,0 @@ -/** - * @file - * IPv4 address API - */ - -/* - * 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_HDR_IP4_ADDR_H -#define LWIP_HDR_IP4_ADDR_H - -#include "lwip/opt.h" -#include "lwip/def.h" - -#if LWIP_IPV4 - -#ifdef __cplusplus -extern "C" { -#endif - -/** This is the aligned version of ip4_addr_t, - used as local variable, on the stack, etc. */ -struct ip4_addr { - u32_t addr; -}; - -/** ip4_addr_t uses a struct for convenience only, so that the same defines can - * operate both on ip4_addr_t as well as on ip4_addr_p_t. */ -typedef struct ip4_addr ip4_addr_t; - -/* Forward declaration to not include netif.h */ -struct netif; - -/** 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! */ - -/** Set an IP address given by the four byte-parts */ -#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->addr = PP_HTONL(LWIP_MAKEU32(a,b,c,d)) - -/** Copy IP address - faster than ip4_addr_set: no NULL check */ -#define ip4_addr_copy(dest, src) ((dest).addr = (src).addr) -/** Safely copy one IP address to another (src may be NULL) */ -#define ip4_addr_set(dest, src) ((dest)->addr = \ - ((src) == NULL ? 0 : \ - (src)->addr)) -/** Set complete address to zero */ -#define ip4_addr_set_zero(ipaddr) ((ipaddr)->addr = 0) -/** Set address to IPADDR_ANY (no need for lwip_htonl()) */ -#define ip4_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY) -/** Set address to loopback address */ -#define ip4_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK)) -/** Check if an address is in the loopback region */ -#define ip4_addr_isloopback(ipaddr) (((ipaddr)->addr & PP_HTONL(IP_CLASSA_NET)) == PP_HTONL(((u32_t)IP_LOOPBACKNET) << 24)) -/** Safely copy one IP address to another and change byte order - * from host- to network-order. */ -#define ip4_addr_set_hton(dest, src) ((dest)->addr = \ - ((src) == NULL ? 0:\ - lwip_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 ip4_addr_get_network(target, host, netmask) do { ((target)->addr = ((host)->addr) & ((netmask)->addr)); } while(0) - -/** - * 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 ip4_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ - (mask)->addr) == \ - ((addr2)->addr & \ - (mask)->addr)) -#define ip4_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) - -#define ip4_addr_isany_val(addr1) ((addr1).addr == IPADDR_ANY) -#define ip4_addr_isany(addr1) ((addr1) == NULL || ip4_addr_isany_val(*(addr1))) - -#define ip4_addr_isbroadcast(addr1, netif) ip4_addr_isbroadcast_u32((addr1)->addr, netif) -u8_t ip4_addr_isbroadcast_u32(u32_t addr, const struct netif *netif); - -#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr) -u8_t ip4_addr_netmask_valid(u32_t netmask); - -#define ip4_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL)) - -#define ip4_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL)) - -#define ip4_addr_debug_print_parts(debug, a, b, c, d) \ - LWIP_DEBUGF(debug, ("%" U16_F ".%" U16_F ".%" U16_F ".%" U16_F, a, b, c, d)) -#define ip4_addr_debug_print(debug, ipaddr) \ - ip4_addr_debug_print_parts(debug, \ - (u16_t)((ipaddr) != NULL ? ip4_addr1_16(ipaddr) : 0), \ - (u16_t)((ipaddr) != NULL ? ip4_addr2_16(ipaddr) : 0), \ - (u16_t)((ipaddr) != NULL ? ip4_addr3_16(ipaddr) : 0), \ - (u16_t)((ipaddr) != NULL ? ip4_addr4_16(ipaddr) : 0)) -#define ip4_addr_debug_print_val(debug, ipaddr) \ - ip4_addr_debug_print_parts(debug, \ - ip4_addr1_16_val(ipaddr), \ - ip4_addr2_16_val(ipaddr), \ - ip4_addr3_16_val(ipaddr), \ - ip4_addr4_16_val(ipaddr)) - -/* Get one byte from the 4-byte address */ -#define ip4_addr_get_byte(ipaddr, idx) (((const u8_t*)(&(ipaddr)->addr))[idx]) -#define ip4_addr1(ipaddr) ip4_addr_get_byte(ipaddr, 0) -#define ip4_addr2(ipaddr) ip4_addr_get_byte(ipaddr, 1) -#define ip4_addr3(ipaddr) ip4_addr_get_byte(ipaddr, 2) -#define ip4_addr4(ipaddr) ip4_addr_get_byte(ipaddr, 3) -/* Get one byte from the 4-byte address, but argument is 'ip4_addr_t', - * not a pointer */ -#define ip4_addr_get_byte_val(ipaddr, idx) ((u8_t)(((ipaddr).addr >> (idx * 8)) & 0xff)) -#define ip4_addr1_val(ipaddr) ip4_addr_get_byte_val(ipaddr, 0) -#define ip4_addr2_val(ipaddr) ip4_addr_get_byte_val(ipaddr, 1) -#define ip4_addr3_val(ipaddr) ip4_addr_get_byte_val(ipaddr, 2) -#define ip4_addr4_val(ipaddr) ip4_addr_get_byte_val(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)) -#define ip4_addr1_16_val(ipaddr) ((u16_t)ip4_addr1_val(ipaddr)) -#define ip4_addr2_16_val(ipaddr) ((u16_t)ip4_addr2_val(ipaddr)) -#define ip4_addr3_16_val(ipaddr) ((u16_t)ip4_addr3_val(ipaddr)) -#define ip4_addr4_16_val(ipaddr) ((u16_t)ip4_addr4_val(ipaddr)) - -#define IP4ADDR_STRLEN_MAX 16 - -/** For backwards compatibility */ -#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr) - -u32_t ipaddr_addr(const char *cp); -int ip4addr_aton(const char *cp, ip4_addr_t *addr); -/** returns ptr to static buffer; not reentrant! */ -char *ip4addr_ntoa(const ip4_addr_t *addr); -char *ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV4 */ - -#endif /* LWIP_HDR_IP_ADDR_H */ diff --git a/core/c/include/lwip/ip4_frag.h b/core/c/include/lwip/ip4_frag.h deleted file mode 100755 index 18cd2d0..0000000 --- a/core/c/include/lwip/ip4_frag.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @file - * IP fragmentation/reassembly - */ - -/* - * 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_HDR_IP4_FRAG_H -#define LWIP_HDR_IP4_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" - -#if LWIP_IPV4 - -#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); -void ip_reass_tmr(void); -struct pbuf * ip4_reass(struct pbuf *p); -#endif /* IP_REASSEMBLY */ - -#if IP_FRAG -#if !LWIP_NETIF_TX_SINGLE_PBUF -#ifndef LWIP_PBUF_CUSTOM_REF_DEFINED -#define LWIP_PBUF_CUSTOM_REF_DEFINED -/** 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 /* LWIP_PBUF_CUSTOM_REF_DEFINED */ -#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ - -err_t ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest); -#endif /* IP_FRAG */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV4 */ - -#endif /* LWIP_HDR_IP4_FRAG_H */ diff --git a/core/c/include/lwip/ip6.h b/core/c/include/lwip/ip6.h deleted file mode 100755 index 706f66d..0000000 --- a/core/c/include/lwip/ip6.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @file - * - * IPv6 layer. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ -#ifndef LWIP_HDR_IP6_H -#define LWIP_HDR_IP6_H - -#include "lwip/opt.h" - -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/ip6_addr.h" -#include "lwip/prot/ip6.h" -#include "lwip/def.h" -#include "lwip/pbuf.h" -#include "lwip/netif.h" - -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct netif *ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest); -const ip_addr_t *ip6_select_source_address(struct netif *netif, const ip6_addr_t * dest); -err_t ip6_input(struct pbuf *p, struct netif *inp); -err_t ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, - u8_t hl, u8_t tc, u8_t nexth); -err_t ip6_output_if(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, - u8_t hl, u8_t tc, u8_t nexth, struct netif *netif); -err_t ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, - u8_t hl, u8_t tc, u8_t nexth, struct netif *netif); -#if LWIP_NETIF_USE_HINTS -err_t ip6_output_hinted(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, - u8_t hl, u8_t tc, u8_t nexth, struct netif_hint *netif_hint); -#endif /* LWIP_NETIF_USE_HINTS */ -#if LWIP_IPV6_MLD -err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value); -#endif /* LWIP_IPV6_MLD */ - -#define ip6_netif_get_local_ip(netif, dest) (((netif) != NULL) ? \ - ip6_select_source_address(netif, dest) : NULL) - -#if IP6_DEBUG -void ip6_debug_print(struct pbuf *p); -#else -#define ip6_debug_print(p) -#endif /* IP6_DEBUG */ - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6 */ - -#endif /* LWIP_HDR_IP6_H */ diff --git a/core/c/include/lwip/ip6_addr.h b/core/c/include/lwip/ip6_addr.h deleted file mode 100755 index 7c1f913..0000000 --- a/core/c/include/lwip/ip6_addr.h +++ /dev/null @@ -1,352 +0,0 @@ -/** - * @file - * - * IPv6 addresses. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * Structs and macros for handling IPv6 addresses. - * - * Please coordinate changes and requests with Ivan Delamer - * - */ -#ifndef LWIP_HDR_IP6_ADDR_H -#define LWIP_HDR_IP6_ADDR_H - -#include "lwip/opt.h" -#include "def.h" - -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/ip6_zone.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** This is the aligned version of ip6_addr_t, - used as local variable, on the stack, etc. */ -struct ip6_addr { - u32_t addr[4]; -#if LWIP_IPV6_SCOPES - u8_t zone; -#endif /* LWIP_IPV6_SCOPES */ -}; - -/** IPv6 address */ -typedef struct ip6_addr ip6_addr_t; - -/** Set an IPv6 partial address given by byte-parts */ -#define IP6_ADDR_PART(ip6addr, index, a,b,c,d) \ - (ip6addr)->addr[index] = PP_HTONL(LWIP_MAKEU32(a,b,c,d)) - -/** Set a full IPv6 address by passing the 4 u32_t indices in network byte order - (use PP_HTONL() for constants) */ -#define IP6_ADDR(ip6addr, idx0, idx1, idx2, idx3) do { \ - (ip6addr)->addr[0] = idx0; \ - (ip6addr)->addr[1] = idx1; \ - (ip6addr)->addr[2] = idx2; \ - (ip6addr)->addr[3] = idx3; \ - ip6_addr_clear_zone(ip6addr); } while(0) - -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK1(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[0]) >> 16) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK2(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[0])) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK3(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[1]) >> 16) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK4(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[1])) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK5(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[2]) >> 16) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK6(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[2])) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK7(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[3]) >> 16) & 0xffff)) -/** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK8(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[3])) & 0xffff)) - -/** Copy IPv6 address - faster than ip6_addr_set: no NULL check */ -#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \ - (dest).addr[1] = (src).addr[1]; \ - (dest).addr[2] = (src).addr[2]; \ - (dest).addr[3] = (src).addr[3]; \ - ip6_addr_copy_zone((dest), (src)); }while(0) -/** Safely copy one IPv6 address to another (src may be NULL) */ -#define ip6_addr_set(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \ - (dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \ - (dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \ - (dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3]; \ - ip6_addr_set_zone((dest), (src) == NULL ? IP6_NO_ZONE : ip6_addr_zone(src)); }while(0) - -/** Copy packed IPv6 address to unpacked IPv6 address; zone is not set */ -#define ip6_addr_copy_from_packed(dest, src) do{(dest).addr[0] = (src).addr[0]; \ - (dest).addr[1] = (src).addr[1]; \ - (dest).addr[2] = (src).addr[2]; \ - (dest).addr[3] = (src).addr[3]; \ - ip6_addr_clear_zone(&dest); }while(0) - -/** Copy unpacked IPv6 address to packed IPv6 address; zone is lost */ -#define ip6_addr_copy_to_packed(dest, src) do{(dest).addr[0] = (src).addr[0]; \ - (dest).addr[1] = (src).addr[1]; \ - (dest).addr[2] = (src).addr[2]; \ - (dest).addr[3] = (src).addr[3]; }while(0) - -/** Set complete address to zero */ -#define ip6_addr_set_zero(ip6addr) do{(ip6addr)->addr[0] = 0; \ - (ip6addr)->addr[1] = 0; \ - (ip6addr)->addr[2] = 0; \ - (ip6addr)->addr[3] = 0; \ - ip6_addr_clear_zone(ip6addr);}while(0) - -/** Set address to ipv6 'any' (no need for lwip_htonl()) */ -#define ip6_addr_set_any(ip6addr) ip6_addr_set_zero(ip6addr) -/** Set address to ipv6 loopback address */ -#define ip6_addr_set_loopback(ip6addr) do{(ip6addr)->addr[0] = 0; \ - (ip6addr)->addr[1] = 0; \ - (ip6addr)->addr[2] = 0; \ - (ip6addr)->addr[3] = PP_HTONL(0x00000001UL); \ - ip6_addr_clear_zone(ip6addr);}while(0) -/** Safely copy one IPv6 address to another and change byte order - * from host- to network-order. */ -#define ip6_addr_set_hton(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : lwip_htonl((src)->addr[0]); \ - (dest)->addr[1] = (src) == NULL ? 0 : lwip_htonl((src)->addr[1]); \ - (dest)->addr[2] = (src) == NULL ? 0 : lwip_htonl((src)->addr[2]); \ - (dest)->addr[3] = (src) == NULL ? 0 : lwip_htonl((src)->addr[3]); \ - ip6_addr_set_zone((dest), (src) == NULL ? IP6_NO_ZONE : ip6_addr_zone(src));}while(0) - - -/** Compare IPv6 networks, ignoring zone information. To be used sparingly! */ -#define ip6_addr_netcmp_zoneless(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ - ((addr1)->addr[1] == (addr2)->addr[1])) - -/** - * Determine if two IPv6 address are on the same network. - * - * @param addr1 IPv6 address 1 - * @param addr2 IPv6 address 2 - * @return 1 if the network identifiers of both address match, 0 if not - */ -#define ip6_addr_netcmp(addr1, addr2) (ip6_addr_netcmp_zoneless((addr1), (addr2)) && \ - ip6_addr_cmp_zone((addr1), (addr2))) - -/* Exact-host comparison *after* ip6_addr_netcmp() succeeded, for efficiency. */ -#define ip6_addr_nethostcmp(addr1, addr2) (((addr1)->addr[2] == (addr2)->addr[2]) && \ - ((addr1)->addr[3] == (addr2)->addr[3])) - -/** Compare IPv6 addresses, ignoring zone information. To be used sparingly! */ -#define ip6_addr_cmp_zoneless(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ - ((addr1)->addr[1] == (addr2)->addr[1]) && \ - ((addr1)->addr[2] == (addr2)->addr[2]) && \ - ((addr1)->addr[3] == (addr2)->addr[3])) -/** - * Determine if two IPv6 addresses are the same. In particular, the address - * part of both must be the same, and the zone must be compatible. - * - * @param addr1 IPv6 address 1 - * @param addr2 IPv6 address 2 - * @return 1 if the addresses are considered equal, 0 if not - */ -#define ip6_addr_cmp(addr1, addr2) (ip6_addr_cmp_zoneless((addr1), (addr2)) && \ - ip6_addr_cmp_zone((addr1), (addr2))) - -/** Compare IPv6 address to packed address and zone */ -#define ip6_addr_cmp_packed(ip6addr, paddr, zone_idx) (((ip6addr)->addr[0] == (paddr)->addr[0]) && \ - ((ip6addr)->addr[1] == (paddr)->addr[1]) && \ - ((ip6addr)->addr[2] == (paddr)->addr[2]) && \ - ((ip6addr)->addr[3] == (paddr)->addr[3]) && \ - ip6_addr_equals_zone((ip6addr), (zone_idx))) - -#define ip6_get_subnet_id(ip6addr) (lwip_htonl((ip6addr)->addr[2]) & 0x0000ffffUL) - -#define ip6_addr_isany_val(ip6addr) (((ip6addr).addr[0] == 0) && \ - ((ip6addr).addr[1] == 0) && \ - ((ip6addr).addr[2] == 0) && \ - ((ip6addr).addr[3] == 0)) -#define ip6_addr_isany(ip6addr) (((ip6addr) == NULL) || ip6_addr_isany_val(*(ip6addr))) - -#define ip6_addr_isloopback(ip6addr) (((ip6addr)->addr[0] == 0UL) && \ - ((ip6addr)->addr[1] == 0UL) && \ - ((ip6addr)->addr[2] == 0UL) && \ - ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) - -#define ip6_addr_isglobal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xe0000000UL)) == PP_HTONL(0x20000000UL)) - -#define ip6_addr_islinklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfe800000UL)) - -#define ip6_addr_issitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfec00000UL)) - -#define ip6_addr_isuniquelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xfe000000UL)) == PP_HTONL(0xfc000000UL)) - -#define ip6_addr_isipv4mappedipv6(ip6addr) (((ip6addr)->addr[0] == 0) && ((ip6addr)->addr[1] == 0) && (((ip6addr)->addr[2]) == PP_HTONL(0x0000FFFFUL))) - -#define ip6_addr_ismulticast(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) -#define ip6_addr_multicast_transient_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00100000UL)) -#define ip6_addr_multicast_prefix_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00200000UL)) -#define ip6_addr_multicast_rendezvous_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00400000UL)) -#define ip6_addr_multicast_scope(ip6addr) ((lwip_htonl((ip6addr)->addr[0]) >> 16) & 0xf) -#define IP6_MULTICAST_SCOPE_RESERVED 0x0 -#define IP6_MULTICAST_SCOPE_RESERVED0 0x0 -#define IP6_MULTICAST_SCOPE_INTERFACE_LOCAL 0x1 -#define IP6_MULTICAST_SCOPE_LINK_LOCAL 0x2 -#define IP6_MULTICAST_SCOPE_RESERVED3 0x3 -#define IP6_MULTICAST_SCOPE_ADMIN_LOCAL 0x4 -#define IP6_MULTICAST_SCOPE_SITE_LOCAL 0x5 -#define IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL 0x8 -#define IP6_MULTICAST_SCOPE_GLOBAL 0xe -#define IP6_MULTICAST_SCOPE_RESERVEDF 0xf -#define ip6_addr_ismulticast_iflocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff010000UL)) -#define ip6_addr_ismulticast_linklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff020000UL)) -#define ip6_addr_ismulticast_adminlocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff040000UL)) -#define ip6_addr_ismulticast_sitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff050000UL)) -#define ip6_addr_ismulticast_orglocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff080000UL)) -#define ip6_addr_ismulticast_global(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff0e0000UL)) - -/* Scoping note: while interface-local and link-local multicast addresses do - * have a scope (i.e., they are meaningful only in the context of a particular - * interface), the following functions are not assigning or comparing zone - * indices. The reason for this is backward compatibility. Any call site that - * produces a non-global multicast address must assign a multicast address as - * appropriate itself. */ - -#define ip6_addr_isallnodes_iflocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff010000UL)) && \ - ((ip6addr)->addr[1] == 0UL) && \ - ((ip6addr)->addr[2] == 0UL) && \ - ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) - -#define ip6_addr_isallnodes_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ - ((ip6addr)->addr[1] == 0UL) && \ - ((ip6addr)->addr[2] == 0UL) && \ - ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) -#define ip6_addr_set_allnodes_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ - (ip6addr)->addr[1] = 0; \ - (ip6addr)->addr[2] = 0; \ - (ip6addr)->addr[3] = PP_HTONL(0x00000001UL); \ - ip6_addr_clear_zone(ip6addr); }while(0) - -#define ip6_addr_isallrouters_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ - ((ip6addr)->addr[1] == 0UL) && \ - ((ip6addr)->addr[2] == 0UL) && \ - ((ip6addr)->addr[3] == PP_HTONL(0x00000002UL))) -#define ip6_addr_set_allrouters_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ - (ip6addr)->addr[1] = 0; \ - (ip6addr)->addr[2] = 0; \ - (ip6addr)->addr[3] = PP_HTONL(0x00000002UL); \ - ip6_addr_clear_zone(ip6addr); }while(0) - -#define ip6_addr_issolicitednode(ip6addr) ( ((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ - ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ - (((ip6addr)->addr[3] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) ) - -#define ip6_addr_set_solicitednode(ip6addr, if_id) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ - (ip6addr)->addr[1] = 0; \ - (ip6addr)->addr[2] = PP_HTONL(0x00000001UL); \ - (ip6addr)->addr[3] = (PP_HTONL(0xff000000UL) | (if_id)); \ - ip6_addr_clear_zone(ip6addr); }while(0) - -#define ip6_addr_cmp_solicitednode(ip6addr, sn_addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ - ((ip6addr)->addr[1] == 0) && \ - ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ - ((ip6addr)->addr[3] == (PP_HTONL(0xff000000UL) | (sn_addr)->addr[3]))) - -/* IPv6 address states. */ -#define IP6_ADDR_INVALID 0x00 -#define IP6_ADDR_TENTATIVE 0x08 -#define IP6_ADDR_TENTATIVE_1 0x09 /* 1 probe sent */ -#define IP6_ADDR_TENTATIVE_2 0x0a /* 2 probes sent */ -#define IP6_ADDR_TENTATIVE_3 0x0b /* 3 probes sent */ -#define IP6_ADDR_TENTATIVE_4 0x0c /* 4 probes sent */ -#define IP6_ADDR_TENTATIVE_5 0x0d /* 5 probes sent */ -#define IP6_ADDR_TENTATIVE_6 0x0e /* 6 probes sent */ -#define IP6_ADDR_TENTATIVE_7 0x0f /* 7 probes sent */ -#define IP6_ADDR_VALID 0x10 /* This bit marks an address as valid (preferred or deprecated) */ -#define IP6_ADDR_PREFERRED 0x30 -#define IP6_ADDR_DEPRECATED 0x10 /* Same as VALID (valid but not preferred) */ -#define IP6_ADDR_DUPLICATED 0x40 /* Failed DAD test, not valid */ - -#define IP6_ADDR_TENTATIVE_COUNT_MASK 0x07 /* 1-7 probes sent */ - -#define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID) -#define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE) -#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */ -#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED) -#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED) -#define ip6_addr_isduplicated(addr_state) (addr_state == IP6_ADDR_DUPLICATED) - -#if LWIP_IPV6_ADDRESS_LIFETIMES -#define IP6_ADDR_LIFE_STATIC (0) -#define IP6_ADDR_LIFE_INFINITE (0xffffffffUL) -#define ip6_addr_life_isstatic(addr_life) ((addr_life) == IP6_ADDR_LIFE_STATIC) -#define ip6_addr_life_isinfinite(addr_life) ((addr_life) == IP6_ADDR_LIFE_INFINITE) -#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ - -#define ip6_addr_debug_print_parts(debug, a, b, c, d, e, f, g, h) \ - LWIP_DEBUGF(debug, ("%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F, \ - a, b, c, d, e, f, g, h)) -#define ip6_addr_debug_print(debug, ipaddr) \ - ip6_addr_debug_print_parts(debug, \ - (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK1(ipaddr) : 0), \ - (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK2(ipaddr) : 0), \ - (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK3(ipaddr) : 0), \ - (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK4(ipaddr) : 0), \ - (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK5(ipaddr) : 0), \ - (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK6(ipaddr) : 0), \ - (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK7(ipaddr) : 0), \ - (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK8(ipaddr) : 0)) -#define ip6_addr_debug_print_val(debug, ipaddr) \ - ip6_addr_debug_print_parts(debug, \ - IP6_ADDR_BLOCK1(&(ipaddr)), \ - IP6_ADDR_BLOCK2(&(ipaddr)), \ - IP6_ADDR_BLOCK3(&(ipaddr)), \ - IP6_ADDR_BLOCK4(&(ipaddr)), \ - IP6_ADDR_BLOCK5(&(ipaddr)), \ - IP6_ADDR_BLOCK6(&(ipaddr)), \ - IP6_ADDR_BLOCK7(&(ipaddr)), \ - IP6_ADDR_BLOCK8(&(ipaddr))) - -#define IP6ADDR_STRLEN_MAX 46 - -int ip6addr_aton(const char *cp, ip6_addr_t *addr); -/** returns ptr to static buffer; not reentrant! */ -char *ip6addr_ntoa(const ip6_addr_t *addr); -char *ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen); - - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6 */ - -#endif /* LWIP_HDR_IP6_ADDR_H */ diff --git a/core/c/include/lwip/ip6_frag.h b/core/c/include/lwip/ip6_frag.h deleted file mode 100755 index 71940dd..0000000 --- a/core/c/include/lwip/ip6_frag.h +++ /dev/null @@ -1,144 +0,0 @@ -/** - * @file - * - * IPv6 fragmentation and reassembly. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ -#ifndef LWIP_HDR_IP6_FRAG_H -#define LWIP_HDR_IP6_FRAG_H - -#include "lwip/opt.h" -#include "lwip/pbuf.h" -#include "lwip/ip6_addr.h" -#include "lwip/ip6.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ - -/** The IPv6 reassembly timer interval in milliseconds. */ -#define IP6_REASS_TMR_INTERVAL 1000 - -/** IP6_FRAG_COPYHEADER==1: for platforms where sizeof(void*) > 4, "struct - * ip6_reass_helper" is too large to be stored in the IPv6 fragment header, and - * will bleed into the header before it, which may be the IPv6 header or an - * extension header. This means that for each first fragment packet, we need to - * 1) make a copy of some IPv6 header fields (src+dest) that we need later on, - * just in case we do overwrite part of the IPv6 header, and 2) make a copy of - * the header data that we overwrote, so that we can restore it before either - * completing reassembly or sending an ICMPv6 reply. The last part is true even - * if this setting is disabled, but if it is enabled, we need to save a bit - * more data (up to the size of a pointer) because we overwrite more. */ -#ifndef IPV6_FRAG_COPYHEADER -#define IPV6_FRAG_COPYHEADER 0 -#endif - -/* With IPV6_FRAG_COPYHEADER==1, a helper structure may (or, depending on the - * presence of extensions, may not) overwrite part of the IP header. Therefore, - * we copy the fields that we need from the IP header for as long as the helper - * structure may still be in place. This is easier than temporarily restoring - * those fields in the IP header each time we need to perform checks on them. */ -#if IPV6_FRAG_COPYHEADER -#define IPV6_FRAG_SRC(ipr) ((ipr)->src) -#define IPV6_FRAG_DEST(ipr) ((ipr)->dest) -#else /* IPV6_FRAG_COPYHEADER */ -#define IPV6_FRAG_SRC(ipr) ((ipr)->iphdr->src) -#define IPV6_FRAG_DEST(ipr) ((ipr)->iphdr->dest) -#endif /* IPV6_FRAG_COPYHEADER */ - -/** IPv6 reassembly helper struct. - * This is exported because memp needs to know the size. - */ -struct ip6_reassdata { - struct ip6_reassdata *next; - struct pbuf *p; - struct ip6_hdr *iphdr; /* pointer to the first (original) IPv6 header */ -#if IPV6_FRAG_COPYHEADER - ip6_addr_p_t src; /* copy of the source address in the IP header */ - ip6_addr_p_t dest; /* copy of the destination address in the IP header */ - /* This buffer (for the part of the original header that we overwrite) will - * be slightly oversized, but we cannot compute the exact size from here. */ - u8_t orig_hdr[sizeof(struct ip6_frag_hdr) + sizeof(void*)]; -#else /* IPV6_FRAG_COPYHEADER */ - /* In this case we still need the buffer, for sending ICMPv6 replies. */ - u8_t orig_hdr[sizeof(struct ip6_frag_hdr)]; -#endif /* IPV6_FRAG_COPYHEADER */ - u32_t identification; - u16_t datagram_len; - u8_t nexth; - u8_t timer; -#if LWIP_IPV6_SCOPES - u8_t src_zone; /* zone of original packet's source address */ - u8_t dest_zone; /* zone of original packet's destination address */ -#endif /* LWIP_IPV6_SCOPES */ -}; - -#define ip6_reass_init() /* Compatibility define */ -void ip6_reass_tmr(void); -struct pbuf *ip6_reass(struct pbuf *p); - -#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ - -#if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */ - -#ifndef LWIP_PBUF_CUSTOM_REF_DEFINED -#define LWIP_PBUF_CUSTOM_REF_DEFINED -/** 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 /* LWIP_PBUF_CUSTOM_REF_DEFINED */ - -err_t ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest); - -#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_IP6_FRAG_H */ diff --git a/core/c/include/lwip/ip6_zone.h b/core/c/include/lwip/ip6_zone.h deleted file mode 100755 index 235141e..0000000 --- a/core/c/include/lwip/ip6_zone.h +++ /dev/null @@ -1,304 +0,0 @@ -/** - * @file - * - * IPv6 address scopes, zones, and scoping policy. - * - * This header provides the means to implement support for IPv6 address scopes, - * as per RFC 4007. An address scope can be either global or more constrained. - * In lwIP, we say that an address "has a scope" or "is scoped" when its scope - * is constrained, in which case the address is meaningful only in a specific - * "zone." For unicast addresses, only link-local addresses have a scope; in - * that case, the scope is the link. For multicast addresses, there are various - * scopes defined by RFC 4007 and others. For any constrained scope, a system - * must establish a (potentially one-to-many) mapping between zones and local - * interfaces. For example, a link-local address is valid on only one link (its - * zone). That link may be attached to one or more local interfaces. The - * decisions on which scopes are constrained and the mapping between zones and - * interfaces is together what we refer to as the "scoping policy" - more on - * this in a bit. - * - * In lwIP, each IPv6 address has an associated zone index. This zone index may - * be set to "no zone" (IP6_NO_ZONE, 0) or an actual zone. We say that an - * address "has a zone" or "is zoned" when its zone index is *not* set to "no - * zone." In lwIP, in principle, each address should be "properly zoned," which - * means that if the address has a zone if and only if has a scope. As such, it - * is a rule that an unscoped (e.g., global) address must never have a zone. - * Even though one could argue that there is always one zone even for global - * scopes, this rule exists for implementation simplicity. Violation of the - * rule will trigger assertions or otherwise result in undesired behavior. - * - * Backward compatibility prevents us from requiring that applications always - * provide properly zoned addresses. We do enforce the rule that the in the - * lwIP link layer (everything below netif->output_ip6() and in particular ND6) - * *all* addresses are properly zoned. Thus, on the output paths down the - * stack, various places deal with the case of addresses that lack a zone. - * Some of them are best-effort for efficiency (e.g. the PCB bind and connect - * API calls' attempts to add missing zones); ultimately the IPv6 output - * handler (@ref ip6_output_if_src) will set a zone if necessary. - * - * Aside from dealing with scoped addresses lacking a zone, a proper IPv6 - * implementation must also ensure that a packet with a scoped source and/or - * destination address does not leave its zone. This is currently implemented - * in the input and forward functions. However, for output, these checks are - * deliberately omitted in order to keep the implementation lightweight. The - * routing algorithm in @ref ip6_route will take decisions such that it will - * not cause zone violations unless the application sets bad addresses, though. - * - * In terms of scoping policy, lwIP implements the default policy from RFC 4007 - * using macros in this file. This policy considers link-local unicast - * addresses and (only) interface-local and link-local multicast addresses as - * having a scope. For all these addresses, the zone is equal to the interface. - * As shown below in this file, it is possible to implement a custom policy. - */ - -/* - * Copyright (c) 2017 The MINIX 3 Project. - * 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: David van Moolenbroek - * - */ -#ifndef LWIP_HDR_IP6_ZONE_H -#define LWIP_HDR_IP6_ZONE_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup ip6_zones IPv6 Zones - * @ingroup ip6 - * @{ - */ - -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -/** Identifier for "no zone". */ -#define IP6_NO_ZONE 0 - -#if LWIP_IPV6_SCOPES - -/** Zone initializer for static IPv6 address initialization, including comma. */ -#define IPADDR6_ZONE_INIT , IP6_NO_ZONE - -/** Return the zone index of the given IPv6 address; possibly "no zone". */ -#define ip6_addr_zone(ip6addr) ((ip6addr)->zone) - -/** Does the given IPv6 address have a zone set? (0/1) */ -#define ip6_addr_has_zone(ip6addr) (ip6_addr_zone(ip6addr) != IP6_NO_ZONE) - -/** Set the zone field of an IPv6 address to a particular value. */ -#define ip6_addr_set_zone(ip6addr, zone_idx) ((ip6addr)->zone = (zone_idx)) - -/** Clear the zone field of an IPv6 address, setting it to "no zone". */ -#define ip6_addr_clear_zone(ip6addr) ((ip6addr)->zone = IP6_NO_ZONE) - -/** Copy the zone field from the second IPv6 address to the first one. */ -#define ip6_addr_copy_zone(ip6addr1, ip6addr2) ((ip6addr1).zone = (ip6addr2).zone) - -/** Is the zone field of the given IPv6 address equal to the given zone index? (0/1) */ -#define ip6_addr_equals_zone(ip6addr, zone_idx) ((ip6addr)->zone == (zone_idx)) - -/** Are the zone fields of the given IPv6 addresses equal? (0/1) - * This macro must only be used on IPv6 addresses of the same scope. */ -#define ip6_addr_cmp_zone(ip6addr1, ip6addr2) ((ip6addr1)->zone == (ip6addr2)->zone) - -/** Symbolic constants for the 'type' parameters in some of the macros. - * These exist for efficiency only, allowing the macros to avoid certain tests - * when the address is known not to be of a certain type. Dead code elimination - * will do the rest. IP6_MULTICAST is supported but currently not optimized. - * @see ip6_addr_has_scope, ip6_addr_assign_zone, ip6_addr_lacks_zone. - */ -enum lwip_ipv6_scope_type -{ - /** Unknown */ - IP6_UNKNOWN = 0, - /** Unicast */ - IP6_UNICAST = 1, - /** Multicast */ - IP6_MULTICAST = 2 -}; - -/** IPV6_CUSTOM_SCOPES: together, the following three macro definitions, - * @ref ip6_addr_has_scope, @ref ip6_addr_assign_zone, and - * @ref ip6_addr_test_zone, completely define the lwIP scoping policy. - * The definitions below implement the default policy from RFC 4007 Sec. 6. - * Should an implementation desire to implement a different policy, it can - * define IPV6_CUSTOM_SCOPES to 1 and supply its own definitions for the three - * macros instead. - */ -#ifndef IPV6_CUSTOM_SCOPES -#define IPV6_CUSTOM_SCOPES 0 -#endif /* !IPV6_CUSTOM_SCOPES */ - -#if !IPV6_CUSTOM_SCOPES - -/** - * Determine whether an IPv6 address has a constrained scope, and as such is - * meaningful only if accompanied by a zone index to identify the scope's zone. - * The given address type may be used to eliminate at compile time certain - * checks that will evaluate to false at run time anyway. - * - * This default implementation follows the default model of RFC 4007, where - * only interface-local and link-local scopes are defined. - * - * Even though the unicast loopback address does have an implied link-local - * scope, in this implementation it does not have an explicitly assigned zone - * index. As such it should not be tested for in this macro. - * - * @param ip6addr the IPv6 address (const); only its address part is examined. - * @param type address type; see @ref lwip_ipv6_scope_type. - * @return 1 if the address has a constrained scope, 0 if it does not. - */ -#define ip6_addr_has_scope(ip6addr, type) \ - (ip6_addr_islinklocal(ip6addr) || (((type) != IP6_UNICAST) && \ - (ip6_addr_ismulticast_iflocal(ip6addr) || \ - ip6_addr_ismulticast_linklocal(ip6addr)))) - -/** - * Assign a zone index to an IPv6 address, based on a network interface. If the - * given address has a scope, the assigned zone index is that scope's zone of - * the given netif; otherwise, the assigned zone index is "no zone". - * - * This default implementation follows the default model of RFC 4007, where - * only interface-local and link-local scopes are defined, and the zone index - * of both of those scopes always equals the index of the network interface. - * As such, this default implementation need not distinguish between different - * constrained scopes when assigning the zone. - * - * @param ip6addr the IPv6 address; its address part is examined, and its zone - * index is assigned. - * @param type address type; see @ref lwip_ipv6_scope_type. - * @param netif the network interface (const). - */ -#define ip6_addr_assign_zone(ip6addr, type, netif) \ - (ip6_addr_set_zone((ip6addr), \ - ip6_addr_has_scope((ip6addr), (type)) ? netif_get_index(netif) : 0)) - -/** - * Test whether an IPv6 address is "zone-compatible" with a network interface. - * That is, test whether the network interface is part of the zone associated - * with the address. For efficiency, this macro is only ever called if the - * given address is either scoped or zoned, and thus, it need not test this. - * If an address is scoped but not zoned, or zoned and not scoped, it is - * considered not zone-compatible with any netif. - * - * This default implementation follows the default model of RFC 4007, where - * only interface-local and link-local scopes are defined, and the zone index - * of both of those scopes always equals the index of the network interface. - * As such, there is always only one matching netif for a specific zone index, - * but all call sites of this macro currently support multiple matching netifs - * as well (at no additional expense in the common case). - * - * @param ip6addr the IPv6 address (const). - * @param netif the network interface (const). - * @return 1 if the address is scope-compatible with the netif, 0 if not. - */ -#define ip6_addr_test_zone(ip6addr, netif) \ - (ip6_addr_equals_zone((ip6addr), netif_get_index(netif))) - -#endif /* !IPV6_CUSTOM_SCOPES */ - -/** Does the given IPv6 address have a scope, and as such should also have a - * zone to be meaningful, but does not actually have a zone? (0/1) */ -#define ip6_addr_lacks_zone(ip6addr, type) \ - (!ip6_addr_has_zone(ip6addr) && ip6_addr_has_scope((ip6addr), (type))) - -/** - * Try to select a zone for a scoped address that does not yet have a zone. - * Called from PCB bind and connect routines, for two reasons: 1) to save on - * this (relatively expensive) selection for every individual packet route - * operation and 2) to allow the application to obtain the selected zone from - * the PCB as is customary for e.g. getsockname/getpeername BSD socket calls. - * - * Ideally, callers would always supply a properly zoned address, in which case - * this function would not be needed. It exists both for compatibility with the - * BSD socket API (which accepts zoneless destination addresses) and for - * backward compatibility with pre-scoping lwIP code. - * - * It may be impossible to select a zone, e.g. if there are no netifs. In that - * case, the address's zone field will be left as is. - * - * @param dest the IPv6 address for which to select and set a zone. - * @param src source IPv6 address (const); may be equal to dest. - */ -#define ip6_addr_select_zone(dest, src) do { struct netif *selected_netif; \ - selected_netif = ip6_route((src), (dest)); \ - if (selected_netif != NULL) { \ - ip6_addr_assign_zone((dest), IP6_UNKNOWN, selected_netif); \ - } } while (0) - -/** - * @} - */ - -#else /* LWIP_IPV6_SCOPES */ - -#define IPADDR6_ZONE_INIT -#define ip6_addr_zone(ip6addr) (IP6_NO_ZONE) -#define ip6_addr_has_zone(ip6addr) (0) -#define ip6_addr_set_zone(ip6addr, zone_idx) -#define ip6_addr_clear_zone(ip6addr) -#define ip6_addr_copy_zone(ip6addr1, ip6addr2) -#define ip6_addr_equals_zone(ip6addr, zone_idx) (1) -#define ip6_addr_cmp_zone(ip6addr1, ip6addr2) (1) -#define IPV6_CUSTOM_SCOPES 0 -#define ip6_addr_has_scope(ip6addr, type) (0) -#define ip6_addr_assign_zone(ip6addr, type, netif) -#define ip6_addr_test_zone(ip6addr, netif) (1) -#define ip6_addr_lacks_zone(ip6addr, type) (0) -#define ip6_addr_select_zone(ip6addr, src) - -#endif /* LWIP_IPV6_SCOPES */ - -#if LWIP_IPV6_SCOPES && LWIP_IPV6_SCOPES_DEBUG - -/** Verify that the given IPv6 address is properly zoned. */ -#define IP6_ADDR_ZONECHECK(ip6addr) LWIP_ASSERT("IPv6 zone check failed", \ - ip6_addr_has_scope(ip6addr, IP6_UNKNOWN) == ip6_addr_has_zone(ip6addr)) - -/** Verify that the given IPv6 address is properly zoned for the given netif. */ -#define IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif) LWIP_ASSERT("IPv6 netif zone check failed", \ - ip6_addr_has_scope(ip6addr, IP6_UNKNOWN) ? \ - (ip6_addr_has_zone(ip6addr) && \ - (((netif) == NULL) || ip6_addr_test_zone((ip6addr), (netif)))) : \ - !ip6_addr_has_zone(ip6addr)) - -#else /* LWIP_IPV6_SCOPES && LWIP_IPV6_SCOPES_DEBUG */ - -#define IP6_ADDR_ZONECHECK(ip6addr) -#define IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif) - -#endif /* LWIP_IPV6_SCOPES && LWIP_IPV6_SCOPES_DEBUG */ - -#endif /* LWIP_IPV6 */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_IP6_ZONE_H */ diff --git a/core/c/include/lwip/ip_addr.h b/core/c/include/lwip/ip_addr.h deleted file mode 100755 index f98fa8a..0000000 --- a/core/c/include/lwip/ip_addr.h +++ /dev/null @@ -1,438 +0,0 @@ -/** - * @file - * IP address API (common IPv4 and IPv6) - */ - -/* - * 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_HDR_IP_ADDR_H -#define LWIP_HDR_IP_ADDR_H - -#include "lwip/opt.h" -#include "lwip/def.h" - -#include "lwip/ip4_addr.h" -#include "lwip/ip6_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** @ingroup ipaddr - * IP address types for use in ip_addr_t.type member. - * @see tcp_new_ip_type(), udp_new_ip_type(), raw_new_ip_type(). - */ -enum lwip_ip_addr_type { - /** IPv4 */ - IPADDR_TYPE_V4 = 0U, - /** IPv6 */ - IPADDR_TYPE_V6 = 6U, - /** IPv4+IPv6 ("dual-stack") */ - IPADDR_TYPE_ANY = 46U -}; - -#if LWIP_IPV4 && LWIP_IPV6 -/** - * @ingroup ipaddr - * A union struct for both IP version's addresses. - * ATTENTION: watch out for its size when adding IPv6 address scope! - */ -typedef struct ip_addr { - union { - ip6_addr_t ip6; - ip4_addr_t ip4; - } u_addr; - /** @ref lwip_ip_addr_type */ - u8_t type; -} ip_addr_t; - -extern const ip_addr_t ip_addr_any_type; - -/** @ingroup ip4addr */ -#define IPADDR4_INIT(u32val) { { { { u32val, 0ul, 0ul, 0ul } IPADDR6_ZONE_INIT } }, IPADDR_TYPE_V4 } -/** @ingroup ip4addr */ -#define IPADDR4_INIT_BYTES(a,b,c,d) IPADDR4_INIT(PP_HTONL(LWIP_MAKEU32(a,b,c,d))) - -/** @ingroup ip6addr */ -#define IPADDR6_INIT(a, b, c, d) { { { { a, b, c, d } IPADDR6_ZONE_INIT } }, IPADDR_TYPE_V6 } -/** @ingroup ip6addr */ -#define IPADDR6_INIT_HOST(a, b, c, d) { { { { PP_HTONL(a), PP_HTONL(b), PP_HTONL(c), PP_HTONL(d) } IPADDR6_ZONE_INIT } }, IPADDR_TYPE_V6 } - -/** @ingroup ipaddr */ -#define IP_IS_ANY_TYPE_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_ANY) -/** @ingroup ipaddr */ -#define IPADDR_ANY_TYPE_INIT { { { { 0ul, 0ul, 0ul, 0ul } IPADDR6_ZONE_INIT } }, IPADDR_TYPE_ANY } - -/** @ingroup ip4addr */ -#define IP_IS_V4_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V4) -/** @ingroup ip6addr */ -#define IP_IS_V6_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V6) -/** @ingroup ip4addr */ -#define IP_IS_V4(ipaddr) (((ipaddr) == NULL) || IP_IS_V4_VAL(*(ipaddr))) -/** @ingroup ip6addr */ -#define IP_IS_V6(ipaddr) (((ipaddr) != NULL) && IP_IS_V6_VAL(*(ipaddr))) - -#define IP_SET_TYPE_VAL(ipaddr, iptype) do { (ipaddr).type = (iptype); }while(0) -#define IP_SET_TYPE(ipaddr, iptype) do { if((ipaddr) != NULL) { IP_SET_TYPE_VAL(*(ipaddr), iptype); }}while(0) -#define IP_GET_TYPE(ipaddr) ((ipaddr)->type) - -#define IP_ADDR_RAW_SIZE(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V4 ? sizeof(ip4_addr_t) : sizeof(ip6_addr_t)) - -#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) (IP_GET_TYPE(&pcb->local_ip) == IP_GET_TYPE(ipaddr)) -#define IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr) (IP_IS_ANY_TYPE_VAL(pcb->local_ip) || IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) - -/** @ingroup ip6addr - * Convert generic ip address to specific protocol version - */ -#define ip_2_ip6(ipaddr) (&((ipaddr)->u_addr.ip6)) -/** @ingroup ip4addr - * Convert generic ip address to specific protocol version - */ -#define ip_2_ip4(ipaddr) (&((ipaddr)->u_addr.ip4)) - -/** @ingroup ip4addr */ -#define IP_ADDR4(ipaddr,a,b,c,d) do { IP4_ADDR(ip_2_ip4(ipaddr),a,b,c,d); \ - IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V4); } while(0) -/** @ingroup ip6addr */ -#define IP_ADDR6(ipaddr,i0,i1,i2,i3) do { IP6_ADDR(ip_2_ip6(ipaddr),i0,i1,i2,i3); \ - IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V6); } while(0) -/** @ingroup ip6addr */ -#define IP_ADDR6_HOST(ipaddr,i0,i1,i2,i3) IP_ADDR6(ipaddr,PP_HTONL(i0),PP_HTONL(i1),PP_HTONL(i2),PP_HTONL(i3)) - -#define ip_clear_no4(ipaddr) do { ip_2_ip6(ipaddr)->addr[1] = \ - ip_2_ip6(ipaddr)->addr[2] = \ - ip_2_ip6(ipaddr)->addr[3] = 0; \ - ip6_addr_clear_zone(ip_2_ip6(ipaddr)); }while(0) - -/** @ingroup ipaddr */ -#define ip_addr_copy(dest, src) do{ IP_SET_TYPE_VAL(dest, IP_GET_TYPE(&src)); if(IP_IS_V6_VAL(src)){ \ - ip6_addr_copy(*ip_2_ip6(&(dest)), *ip_2_ip6(&(src))); }else{ \ - ip4_addr_copy(*ip_2_ip4(&(dest)), *ip_2_ip4(&(src))); ip_clear_no4(&dest); }}while(0) -/** @ingroup ip6addr */ -#define ip_addr_copy_from_ip6(dest, src) do{ \ - ip6_addr_copy(*ip_2_ip6(&(dest)), src); IP_SET_TYPE_VAL(dest, IPADDR_TYPE_V6); }while(0) -/** @ingroup ip6addr */ -#define ip_addr_copy_from_ip6_packed(dest, src) do{ \ - ip6_addr_copy_from_packed(*ip_2_ip6(&(dest)), src); IP_SET_TYPE_VAL(dest, IPADDR_TYPE_V6); }while(0) -/** @ingroup ip4addr */ -#define ip_addr_copy_from_ip4(dest, src) do{ \ - ip4_addr_copy(*ip_2_ip4(&(dest)), src); IP_SET_TYPE_VAL(dest, IPADDR_TYPE_V4); ip_clear_no4(&dest); }while(0) -/** @ingroup ip4addr */ -#define ip_addr_set_ip4_u32(ipaddr, val) do{if(ipaddr){ip4_addr_set_u32(ip_2_ip4(ipaddr), val); \ - IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); ip_clear_no4(ipaddr); }}while(0) -/** @ingroup ip4addr */ -#define ip_addr_set_ip4_u32_val(ipaddr, val) do{ ip4_addr_set_u32(ip_2_ip4(&(ipaddr)), val); \ - IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); ip_clear_no4(&ipaddr); }while(0) -/** @ingroup ip4addr */ -#define ip_addr_get_ip4_u32(ipaddr) (((ipaddr) && IP_IS_V4(ipaddr)) ? \ - ip4_addr_get_u32(ip_2_ip4(ipaddr)) : 0) -/** @ingroup ipaddr */ -#define ip_addr_set(dest, src) do{ IP_SET_TYPE(dest, IP_GET_TYPE(src)); if(IP_IS_V6(src)){ \ - ip6_addr_set(ip_2_ip6(dest), ip_2_ip6(src)); }else{ \ - ip4_addr_set(ip_2_ip4(dest), ip_2_ip4(src)); ip_clear_no4(dest); }}while(0) -/** @ingroup ipaddr */ -#define ip_addr_set_ipaddr(dest, src) ip_addr_set(dest, src) -/** @ingroup ipaddr */ -#define ip_addr_set_zero(ipaddr) do{ \ - ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, 0); }while(0) -/** @ingroup ip5addr */ -#define ip_addr_set_zero_ip4(ipaddr) do{ \ - ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); }while(0) -/** @ingroup ip6addr */ -#define ip_addr_set_zero_ip6(ipaddr) do{ \ - ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6); }while(0) -/** @ingroup ipaddr */ -#define ip_addr_set_any(is_ipv6, ipaddr) do{if(is_ipv6){ \ - ip6_addr_set_any(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6); }else{ \ - ip4_addr_set_any(ip_2_ip4(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); ip_clear_no4(ipaddr); }}while(0) -/** @ingroup ipaddr */ -#define ip_addr_set_any_val(is_ipv6, ipaddr) do{if(is_ipv6){ \ - ip6_addr_set_any(ip_2_ip6(&(ipaddr))); IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V6); }else{ \ - ip4_addr_set_any(ip_2_ip4(&(ipaddr))); IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); ip_clear_no4(&ipaddr); }}while(0) -/** @ingroup ipaddr */ -#define ip_addr_set_loopback(is_ipv6, ipaddr) do{if(is_ipv6){ \ - ip6_addr_set_loopback(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6); }else{ \ - ip4_addr_set_loopback(ip_2_ip4(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); ip_clear_no4(ipaddr); }}while(0) -/** @ingroup ipaddr */ -#define ip_addr_set_loopback_val(is_ipv6, ipaddr) do{if(is_ipv6){ \ - ip6_addr_set_loopback(ip_2_ip6(&(ipaddr))); IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V6); }else{ \ - ip4_addr_set_loopback(ip_2_ip4(&(ipaddr))); IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); ip_clear_no4(&ipaddr); }}while(0) -/** @ingroup ipaddr */ -#define ip_addr_set_hton(dest, src) do{if(IP_IS_V6(src)){ \ - ip6_addr_set_hton(ip_2_ip6(dest), ip_2_ip6(src)); IP_SET_TYPE(dest, IPADDR_TYPE_V6); }else{ \ - ip4_addr_set_hton(ip_2_ip4(dest), ip_2_ip4(src)); IP_SET_TYPE(dest, IPADDR_TYPE_V4); ip_clear_no4(ipaddr); }}while(0) -/** @ingroup ipaddr */ -#define ip_addr_get_network(target, host, netmask) do{if(IP_IS_V6(host)){ \ - ip4_addr_set_zero(ip_2_ip4(target)); IP_SET_TYPE(target, IPADDR_TYPE_V6); } else { \ - ip4_addr_get_network(ip_2_ip4(target), ip_2_ip4(host), ip_2_ip4(netmask)); IP_SET_TYPE(target, IPADDR_TYPE_V4); }}while(0) -/** @ingroup ipaddr */ -#define ip_addr_netcmp(addr1, addr2, mask) ((IP_IS_V6(addr1) && IP_IS_V6(addr2)) ? \ - 0 : \ - ip4_addr_netcmp(ip_2_ip4(addr1), ip_2_ip4(addr2), mask)) -/** @ingroup ipaddr */ -#define ip_addr_cmp(addr1, addr2) ((IP_GET_TYPE(addr1) != IP_GET_TYPE(addr2)) ? 0 : (IP_IS_V6_VAL(*(addr1)) ? \ - ip6_addr_cmp(ip_2_ip6(addr1), ip_2_ip6(addr2)) : \ - ip4_addr_cmp(ip_2_ip4(addr1), ip_2_ip4(addr2)))) -/** @ingroup ipaddr */ -#define ip_addr_cmp_zoneless(addr1, addr2) ((IP_GET_TYPE(addr1) != IP_GET_TYPE(addr2)) ? 0 : (IP_IS_V6_VAL(*(addr1)) ? \ - ip6_addr_cmp_zoneless(ip_2_ip6(addr1), ip_2_ip6(addr2)) : \ - ip4_addr_cmp(ip_2_ip4(addr1), ip_2_ip4(addr2)))) -/** @ingroup ipaddr */ -#define ip_addr_isany(ipaddr) (((ipaddr) == NULL) ? 1 : ((IP_IS_V6(ipaddr)) ? \ - ip6_addr_isany(ip_2_ip6(ipaddr)) : \ - ip4_addr_isany(ip_2_ip4(ipaddr)))) -/** @ingroup ipaddr */ -#define ip_addr_isany_val(ipaddr) ((IP_IS_V6_VAL(ipaddr)) ? \ - ip6_addr_isany_val(*ip_2_ip6(&(ipaddr))) : \ - ip4_addr_isany_val(*ip_2_ip4(&(ipaddr)))) -/** @ingroup ipaddr */ -#define ip_addr_isbroadcast(ipaddr, netif) ((IP_IS_V6(ipaddr)) ? \ - 0 : \ - ip4_addr_isbroadcast(ip_2_ip4(ipaddr), netif)) -/** @ingroup ipaddr */ -#define ip_addr_ismulticast(ipaddr) ((IP_IS_V6(ipaddr)) ? \ - ip6_addr_ismulticast(ip_2_ip6(ipaddr)) : \ - ip4_addr_ismulticast(ip_2_ip4(ipaddr))) -/** @ingroup ipaddr */ -#define ip_addr_isloopback(ipaddr) ((IP_IS_V6(ipaddr)) ? \ - ip6_addr_isloopback(ip_2_ip6(ipaddr)) : \ - ip4_addr_isloopback(ip_2_ip4(ipaddr))) -/** @ingroup ipaddr */ -#define ip_addr_islinklocal(ipaddr) ((IP_IS_V6(ipaddr)) ? \ - ip6_addr_islinklocal(ip_2_ip6(ipaddr)) : \ - ip4_addr_islinklocal(ip_2_ip4(ipaddr))) -#define ip_addr_debug_print(debug, ipaddr) do { if(IP_IS_V6(ipaddr)) { \ - ip6_addr_debug_print(debug, ip_2_ip6(ipaddr)); } else { \ - ip4_addr_debug_print(debug, ip_2_ip4(ipaddr)); }}while(0) -#define ip_addr_debug_print_val(debug, ipaddr) do { if(IP_IS_V6_VAL(ipaddr)) { \ - ip6_addr_debug_print_val(debug, *ip_2_ip6(&(ipaddr))); } else { \ - ip4_addr_debug_print_val(debug, *ip_2_ip4(&(ipaddr))); }}while(0) -char *ipaddr_ntoa(const ip_addr_t *addr); -char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen); -int ipaddr_aton(const char *cp, ip_addr_t *addr); - -/** @ingroup ipaddr */ -#define IPADDR_STRLEN_MAX IP6ADDR_STRLEN_MAX - -/** @ingroup ipaddr */ -#define ip4_2_ipv4_mapped_ipv6(ip6addr, ip4addr) do { \ - (ip6addr)->addr[3] = (ip4addr)->addr; \ - (ip6addr)->addr[2] = PP_HTONL(0x0000FFFFUL); \ - (ip6addr)->addr[1] = 0; \ - (ip6addr)->addr[0] = 0; \ - ip6_addr_clear_zone(ip6addr); } while(0); - -/** @ingroup ipaddr */ -#define unmap_ipv4_mapped_ipv6(ip4addr, ip6addr) \ - (ip4addr)->addr = (ip6addr)->addr[3]; - -#define IP46_ADDR_ANY(type) (((type) == IPADDR_TYPE_V6)? IP6_ADDR_ANY : IP4_ADDR_ANY) - -#else /* LWIP_IPV4 && LWIP_IPV6 */ - -#define IP_ADDR_PCB_VERSION_MATCH(addr, pcb) 1 -#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) 1 - -#define ip_addr_set_any_val(is_ipv6, ipaddr) ip_addr_set_any(is_ipv6, &(ipaddr)) -#define ip_addr_set_loopback_val(is_ipv6, ipaddr) ip_addr_set_loopback(is_ipv6, &(ipaddr)) - -#if LWIP_IPV4 - -typedef ip4_addr_t ip_addr_t; -#define IPADDR4_INIT(u32val) { u32val } -#define IPADDR4_INIT_BYTES(a,b,c,d) IPADDR4_INIT(PP_HTONL(LWIP_MAKEU32(a,b,c,d))) -#define IP_IS_V4_VAL(ipaddr) 1 -#define IP_IS_V6_VAL(ipaddr) 0 -#define IP_IS_V4(ipaddr) 1 -#define IP_IS_V6(ipaddr) 0 -#define IP_IS_ANY_TYPE_VAL(ipaddr) 0 -#define IP_SET_TYPE_VAL(ipaddr, iptype) -#define IP_SET_TYPE(ipaddr, iptype) -#define IP_GET_TYPE(ipaddr) IPADDR_TYPE_V4 -#define IP_ADDR_RAW_SIZE(ipaddr) sizeof(ip4_addr_t) -#define ip_2_ip4(ipaddr) (ipaddr) -#define IP_ADDR4(ipaddr,a,b,c,d) IP4_ADDR(ipaddr,a,b,c,d) - -#define ip_addr_copy(dest, src) ip4_addr_copy(dest, src) -#define ip_addr_copy_from_ip4(dest, src) ip4_addr_copy(dest, src) -#define ip_addr_set_ip4_u32(ipaddr, val) ip4_addr_set_u32(ip_2_ip4(ipaddr), val) -#define ip_addr_set_ip4_u32_val(ipaddr, val) ip_addr_set_ip4_u32(&(ipaddr), val) -#define ip_addr_get_ip4_u32(ipaddr) ip4_addr_get_u32(ip_2_ip4(ipaddr)) -#define ip_addr_set(dest, src) ip4_addr_set(dest, src) -#define ip_addr_set_ipaddr(dest, src) ip4_addr_set(dest, src) -#define ip_addr_set_zero(ipaddr) ip4_addr_set_zero(ipaddr) -#define ip_addr_set_zero_ip4(ipaddr) ip4_addr_set_zero(ipaddr) -#define ip_addr_set_any(is_ipv6, ipaddr) ip4_addr_set_any(ipaddr) -#define ip_addr_set_loopback(is_ipv6, ipaddr) ip4_addr_set_loopback(ipaddr) -#define ip_addr_set_hton(dest, src) ip4_addr_set_hton(dest, src) -#define ip_addr_get_network(target, host, mask) ip4_addr_get_network(target, host, mask) -#define ip_addr_netcmp(addr1, addr2, mask) ip4_addr_netcmp(addr1, addr2, mask) -#define ip_addr_cmp(addr1, addr2) ip4_addr_cmp(addr1, addr2) -#define ip_addr_isany(ipaddr) ip4_addr_isany(ipaddr) -#define ip_addr_isany_val(ipaddr) ip4_addr_isany_val(ipaddr) -#define ip_addr_isloopback(ipaddr) ip4_addr_isloopback(ipaddr) -#define ip_addr_islinklocal(ipaddr) ip4_addr_islinklocal(ipaddr) -#define ip_addr_isbroadcast(addr, netif) ip4_addr_isbroadcast(addr, netif) -#define ip_addr_ismulticast(ipaddr) ip4_addr_ismulticast(ipaddr) -#define ip_addr_debug_print(debug, ipaddr) ip4_addr_debug_print(debug, ipaddr) -#define ip_addr_debug_print_val(debug, ipaddr) ip4_addr_debug_print_val(debug, ipaddr) -#define ipaddr_ntoa(ipaddr) ip4addr_ntoa(ipaddr) -#define ipaddr_ntoa_r(ipaddr, buf, buflen) ip4addr_ntoa_r(ipaddr, buf, buflen) -#define ipaddr_aton(cp, addr) ip4addr_aton(cp, addr) - -#define IPADDR_STRLEN_MAX IP4ADDR_STRLEN_MAX - -#define IP46_ADDR_ANY(type) (IP4_ADDR_ANY) - -#else /* LWIP_IPV4 */ - -typedef ip6_addr_t ip_addr_t; -#define IPADDR6_INIT(a, b, c, d) { { a, b, c, d } IPADDR6_ZONE_INIT } -#define IPADDR6_INIT_HOST(a, b, c, d) { { PP_HTONL(a), PP_HTONL(b), PP_HTONL(c), PP_HTONL(d) } IPADDR6_ZONE_INIT } -#define IP_IS_V4_VAL(ipaddr) 0 -#define IP_IS_V6_VAL(ipaddr) 1 -#define IP_IS_V4(ipaddr) 0 -#define IP_IS_V6(ipaddr) 1 -#define IP_IS_ANY_TYPE_VAL(ipaddr) 0 -#define IP_SET_TYPE_VAL(ipaddr, iptype) -#define IP_SET_TYPE(ipaddr, iptype) -#define IP_GET_TYPE(ipaddr) IPADDR_TYPE_V6 -#define IP_ADDR_RAW_SIZE(ipaddr) sizeof(ip6_addr_t) -#define ip_2_ip6(ipaddr) (ipaddr) -#define IP_ADDR6(ipaddr,i0,i1,i2,i3) IP6_ADDR(ipaddr,i0,i1,i2,i3) -#define IP_ADDR6_HOST(ipaddr,i0,i1,i2,i3) IP_ADDR6(ipaddr,PP_HTONL(i0),PP_HTONL(i1),PP_HTONL(i2),PP_HTONL(i3)) - -#define ip_addr_copy(dest, src) ip6_addr_copy(dest, src) -#define ip_addr_copy_from_ip6(dest, src) ip6_addr_copy(dest, src) -#define ip_addr_copy_from_ip6_packed(dest, src) ip6_addr_copy_from_packed(dest, src) -#define ip_addr_set(dest, src) ip6_addr_set(dest, src) -#define ip_addr_set_ipaddr(dest, src) ip6_addr_set(dest, src) -#define ip_addr_set_zero(ipaddr) ip6_addr_set_zero(ipaddr) -#define ip_addr_set_zero_ip6(ipaddr) ip6_addr_set_zero(ipaddr) -#define ip_addr_set_any(is_ipv6, ipaddr) ip6_addr_set_any(ipaddr) -#define ip_addr_set_loopback(is_ipv6, ipaddr) ip6_addr_set_loopback(ipaddr) -#define ip_addr_set_hton(dest, src) ip6_addr_set_hton(dest, src) -#define ip_addr_get_network(target, host, mask) ip6_addr_set_zero(target) -#define ip_addr_netcmp(addr1, addr2, mask) 0 -#define ip_addr_cmp(addr1, addr2) ip6_addr_cmp(addr1, addr2) -#define ip_addr_cmp_zoneless(addr1, addr2) ip6_addr_cmp_zoneless(addr1, addr2) -#define ip_addr_isany(ipaddr) ip6_addr_isany(ipaddr) -#define ip_addr_isany_val(ipaddr) ip6_addr_isany_val(ipaddr) -#define ip_addr_isloopback(ipaddr) ip6_addr_isloopback(ipaddr) -#define ip_addr_islinklocal(ipaddr) ip6_addr_islinklocal(ipaddr) -#define ip_addr_isbroadcast(addr, netif) 0 -#define ip_addr_ismulticast(ipaddr) ip6_addr_ismulticast(ipaddr) -#define ip_addr_debug_print(debug, ipaddr) ip6_addr_debug_print(debug, ipaddr) -#define ip_addr_debug_print_val(debug, ipaddr) ip6_addr_debug_print_val(debug, ipaddr) -#define ipaddr_ntoa(ipaddr) ip6addr_ntoa(ipaddr) -#define ipaddr_ntoa_r(ipaddr, buf, buflen) ip6addr_ntoa_r(ipaddr, buf, buflen) -#define ipaddr_aton(cp, addr) ip6addr_aton(cp, addr) - -#define IPADDR_STRLEN_MAX IP6ADDR_STRLEN_MAX - -#define IP46_ADDR_ANY(type) (IP6_ADDR_ANY) - -#endif /* LWIP_IPV4 */ -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - -#if LWIP_IPV4 - -extern const ip_addr_t ip_addr_any; -extern const ip_addr_t ip_addr_broadcast; - -/** - * @ingroup ip4addr - * Can be used as a fixed/const ip_addr_t - * for the IP wildcard. - * Defined to @ref IP4_ADDR_ANY when IPv4 is enabled. - * Defined to @ref IP6_ADDR_ANY in IPv6 only systems. - * Use this if you can handle IPv4 _AND_ IPv6 addresses. - * Use @ref IP4_ADDR_ANY or @ref IP6_ADDR_ANY when the IP - * type matters. - */ -#define IP_ADDR_ANY IP4_ADDR_ANY -/** - * @ingroup ip4addr - * Can be used as a fixed/const ip_addr_t - * for the IPv4 wildcard and the broadcast address - */ -#define IP4_ADDR_ANY (&ip_addr_any) -/** - * @ingroup ip4addr - * Can be used as a fixed/const ip4_addr_t - * for the wildcard and the broadcast address - */ -#define IP4_ADDR_ANY4 (ip_2_ip4(&ip_addr_any)) - -/** @ingroup ip4addr */ -#define IP_ADDR_BROADCAST (&ip_addr_broadcast) -/** @ingroup ip4addr */ -#define IP4_ADDR_BROADCAST (ip_2_ip4(&ip_addr_broadcast)) - -#endif /* LWIP_IPV4*/ - -#if LWIP_IPV6 - -extern const ip_addr_t ip6_addr_any; - -/** - * @ingroup ip6addr - * IP6_ADDR_ANY can be used as a fixed ip_addr_t - * for the IPv6 wildcard address - */ -#define IP6_ADDR_ANY (&ip6_addr_any) -/** - * @ingroup ip6addr - * IP6_ADDR_ANY6 can be used as a fixed ip6_addr_t - * for the IPv6 wildcard address - */ -#define IP6_ADDR_ANY6 (ip_2_ip6(&ip6_addr_any)) - -#if !LWIP_IPV4 -/** IPv6-only configurations */ -#define IP_ADDR_ANY IP6_ADDR_ANY -#endif /* !LWIP_IPV4 */ - -#endif - -#if LWIP_IPV4 && LWIP_IPV6 -/** @ingroup ipaddr */ -#define IP_ANY_TYPE (&ip_addr_any_type) -#else -#define IP_ANY_TYPE IP_ADDR_ANY -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_IP_ADDR_H */ diff --git a/core/c/include/lwip/mem.h b/core/c/include/lwip/mem.h deleted file mode 100755 index 424de91..0000000 --- a/core/c/include/lwip/mem.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @file - * Heap API - */ - -/* - * 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_HDR_MEM_H -#define LWIP_HDR_MEM_H - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if MEM_LIBC_MALLOC - -#include "lwip/arch.h" - -typedef size_t mem_size_t; -#define MEM_SIZE_F SZT_F - -#elif MEM_USE_POOLS - -typedef u16_t mem_size_t; -#define MEM_SIZE_F U16_F - -#else - -/* 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 */ -#endif - -void mem_init(void); -void *mem_trim(void *mem, mem_size_t size); -void *mem_malloc(mem_size_t size); -void *mem_calloc(mem_size_t count, mem_size_t size); -void mem_free(void *mem); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_MEM_H */ diff --git a/core/c/include/lwip/memp.h b/core/c/include/lwip/memp.h deleted file mode 100755 index 74ac818..0000000 --- a/core/c/include/lwip/memp.h +++ /dev/null @@ -1,155 +0,0 @@ -/** - * @file - * Memory pool API - */ - -/* - * 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_HDR_MEMP_H -#define LWIP_HDR_MEMP_H - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* run once with empty definition to handle all custom includes in lwippools.h */ -#define LWIP_MEMPOOL(name,num,size,desc) -#include "lwip/priv/memp_std.h" - -/** 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) MEMP_##name, -#include "lwip/priv/memp_std.h" - MEMP_MAX -} memp_t; - -#include "lwip/priv/memp_priv.h" -#include "lwip/stats.h" - -extern const struct memp_desc* const memp_pools[MEMP_MAX]; - -/** - * @ingroup mempool - * Declare prototype for private memory pool if it is used in multiple files - */ -#define LWIP_MEMPOOL_PROTOTYPE(name) extern const struct memp_desc memp_ ## name - -#if MEMP_MEM_MALLOC - -#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ - LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \ - const struct memp_desc memp_ ## name = { \ - DECLARE_LWIP_MEMPOOL_DESC(desc) \ - LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \ - LWIP_MEM_ALIGN_SIZE(size) \ - }; - -#else /* MEMP_MEM_MALLOC */ - -/** - * @ingroup mempool - * Declare a private memory pool - * Private mempools example: - * .h: only when pool is used in multiple .c files: LWIP_MEMPOOL_PROTOTYPE(my_private_pool); - * .c: - * - in global variables section: LWIP_MEMPOOL_DECLARE(my_private_pool, 10, sizeof(foo), "Some description") - * - call ONCE before using pool (e.g. in some init() function): LWIP_MEMPOOL_INIT(my_private_pool); - * - allocate: void* my_new_mem = LWIP_MEMPOOL_ALLOC(my_private_pool); - * - free: LWIP_MEMPOOL_FREE(my_private_pool, my_new_mem); - * - * To relocate a pool, declare it as extern in cc.h. Example for GCC: - * extern u8_t \_\_attribute\_\_((section(".onchip_mem"))) memp_memory_my_private_pool_base[]; - */ -#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ - LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_ ## name ## _base, ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); \ - \ - LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \ - \ - static struct memp *memp_tab_ ## name; \ - \ - const struct memp_desc memp_ ## name = { \ - DECLARE_LWIP_MEMPOOL_DESC(desc) \ - LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \ - LWIP_MEM_ALIGN_SIZE(size), \ - (num), \ - memp_memory_ ## name ## _base, \ - &memp_tab_ ## name \ - }; - -#endif /* MEMP_MEM_MALLOC */ - -/** - * @ingroup mempool - * Initialize a private memory pool - */ -#define LWIP_MEMPOOL_INIT(name) memp_init_pool(&memp_ ## name) -/** - * @ingroup mempool - * Allocate from a private memory pool - */ -#define LWIP_MEMPOOL_ALLOC(name) memp_malloc_pool(&memp_ ## name) -/** - * @ingroup mempool - * Free element from a private memory pool - */ -#define LWIP_MEMPOOL_FREE(name, x) memp_free_pool(&memp_ ## name, (x)) - -#if MEM_USE_POOLS -/** This structure is used to save the pool one element came from. - * This has to be defined here as it is required for pool size calculation. */ -struct memp_malloc_helper -{ - memp_t poolnr; -#if MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) - u16_t size; -#endif /* MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) */ -}; -#endif /* MEM_USE_POOLS */ - -void memp_init(void); - -#if MEMP_OVERFLOW_CHECK -void *memp_malloc_fn(memp_t type, const char* file, const int line); -#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__) -#else -void *memp_malloc(memp_t type); -#endif -void memp_free(memp_t type, void *mem); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_MEMP_H */ diff --git a/core/c/include/lwip/mld6.h b/core/c/include/lwip/mld6.h deleted file mode 100755 index f8c99d9..0000000 --- a/core/c/include/lwip/mld6.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @file - * - * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. - * No support for MLDv2. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#ifndef LWIP_HDR_MLD6_H -#define LWIP_HDR_MLD6_H - -#include "lwip/opt.h" - -#if LWIP_IPV6_MLD && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/pbuf.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** MLD group */ -struct mld_group { - /** next link */ - struct mld_group *next; - /** multicast address */ - ip6_addr_t group_address; - /** signifies we were the last person to report */ - u8_t last_reporter_flag; - /** current state of the group */ - u8_t group_state; - /** timer for reporting */ - u16_t timer; - /** counter of simultaneous uses */ - u8_t use; -}; - -#define MLD6_TMR_INTERVAL 100 /* Milliseconds */ - -err_t mld6_stop(struct netif *netif); -void mld6_report_groups(struct netif *netif); -void mld6_tmr(void); -struct mld_group *mld6_lookfor_group(struct netif *ifp, const ip6_addr_t *addr); -void mld6_input(struct pbuf *p, struct netif *inp); -err_t mld6_joingroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr); -err_t mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr); -err_t mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr); -err_t mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr); - -/** @ingroup mld6 - * Get list head of MLD6 groups for netif. - * Note: The allnodes group IP is NOT in the list, since it must always - * be received for correct IPv6 operation. - * @see @ref netif_set_mld_mac_filter() - */ -#define netif_mld6_data(netif) ((struct mld_group *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6)) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6_MLD && LWIP_IPV6 */ - -#endif /* LWIP_HDR_MLD6_H */ diff --git a/core/c/include/lwip/nd6.h b/core/c/include/lwip/nd6.h deleted file mode 100755 index 89137d5..0000000 --- a/core/c/include/lwip/nd6.h +++ /dev/null @@ -1,90 +0,0 @@ -/** - * @file - * - * Neighbor discovery and stateless address autoconfiguration for IPv6. - * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 - * (Address autoconfiguration). - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#ifndef LWIP_HDR_ND6_H -#define LWIP_HDR_ND6_H - -#include "lwip/opt.h" - -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/ip6_addr.h" -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** 1 second period */ -#define ND6_TMR_INTERVAL 1000 - -/** Router solicitations are sent in 4 second intervals (see RFC 4861, ch. 6.3.7) */ -#ifndef ND6_RTR_SOLICITATION_INTERVAL -#define ND6_RTR_SOLICITATION_INTERVAL 4000 -#endif - -struct pbuf; -struct netif; - -void nd6_tmr(void); -void nd6_input(struct pbuf *p, struct netif *inp); -void nd6_clear_destination_cache(void); -struct netif *nd6_find_route(const ip6_addr_t *ip6addr); -err_t nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp); -u16_t nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif); -#if LWIP_ND6_TCP_REACHABILITY_HINTS -void nd6_reachability_hint(const ip6_addr_t *ip6addr); -#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ -void nd6_cleanup_netif(struct netif *netif); -#if LWIP_IPV6_MLD -void nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state); -#endif /* LWIP_IPV6_MLD */ -void nd6_restart_netif(struct netif *netif); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6 */ - -#endif /* LWIP_HDR_ND6_H */ diff --git a/core/c/include/lwip/netbuf.h b/core/c/include/lwip/netbuf.h deleted file mode 100755 index e92c934..0000000 --- a/core/c/include/lwip/netbuf.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @file - * netbuf API (for netconn API) - */ - -/* - * 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_HDR_NETBUF_H -#define LWIP_HDR_NETBUF_H - -#include "lwip/opt.h" - -#if LWIP_NETCONN || LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ -/* Note: Netconn API is always available when sockets are enabled - - * sockets are implemented on top of them */ - -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" -#include "lwip/ip6_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** This netbuf has dest-addr/port set */ -#define NETBUF_FLAG_DESTADDR 0x01 -/** This netbuf includes a checksum */ -#define NETBUF_FLAG_CHKSUM 0x02 - -/** "Network buffer" - contains data and addressing info */ -struct netbuf { - struct pbuf *p, *ptr; - ip_addr_t addr; - u16_t port; -#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY - u8_t flags; - 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); -void netbuf_delete (struct netbuf *buf); -void * netbuf_alloc (struct netbuf *buf, u16_t size); -void netbuf_free (struct netbuf *buf); -err_t netbuf_ref (struct netbuf *buf, - const void *dataptr, u16_t size); -void netbuf_chain (struct netbuf *head, struct netbuf *tail); - -err_t netbuf_data (struct netbuf *buf, - void **dataptr, u16_t *len); -s8_t netbuf_next (struct netbuf *buf); -void netbuf_first (struct netbuf *buf); - - -#define netbuf_copy_partial(buf, dataptr, len, offset) \ - pbuf_copy_partial((buf)->p, (dataptr), (len), (offset)) -#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) -#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) -#define netbuf_len(buf) ((buf)->p->tot_len) -#define netbuf_fromaddr(buf) (&((buf)->addr)) -#define netbuf_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)->toaddr), destaddr) -#if LWIP_CHECKSUM_ON_COPY -#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0) -#else /* LWIP_CHECKSUM_ON_COPY */ -#define netbuf_destport(buf) ((buf)->toport_chksum) -#endif /* LWIP_CHECKSUM_ON_COPY */ -#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_NETCONN || LWIP_SOCKET */ - -#endif /* LWIP_HDR_NETBUF_H */ diff --git a/core/c/include/lwip/netdb.h b/core/c/include/lwip/netdb.h deleted file mode 100755 index 6aae914..0000000 --- a/core/c/include/lwip/netdb.h +++ /dev/null @@ -1,150 +0,0 @@ -/** - * @file - * NETDB API (sockets) - */ - -/* - * 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_HDR_NETDB_H -#define LWIP_HDR_NETDB_H - -#include "lwip/opt.h" - -#if LWIP_DNS && LWIP_SOCKET - -#include "lwip/arch.h" -#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_DEFINE_FLAGS -#define LWIP_DNS_API_DEFINE_FLAGS 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 EAI_FAMILY 204 - -#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_DEFINE_FLAGS -/* input flags for struct addrinfo */ -#define AI_PASSIVE 0x01 -#define AI_CANONNAME 0x02 -#define AI_NUMERICHOST 0x04 -#define AI_NUMERICSERV 0x08 -#define AI_V4MAPPED 0x10 -#define AI_ALL 0x20 -#define AI_ADDRCONFIG 0x40 -#endif /* LWIP_DNS_API_DEFINE_FLAGS */ - -#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 */ - -#define NETDB_ELEM_SIZE (sizeof(struct addrinfo) + sizeof(struct sockaddr_storage) + DNS_MAX_NAME_LENGTH + 1) - -#if LWIP_DNS_API_DECLARE_H_ERRNO -/* application accessible 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 -/** @ingroup netdbapi */ -#define gethostbyname(name) lwip_gethostbyname(name) -/** @ingroup netdbapi */ -#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ - lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) -/** @ingroup netdbapi */ -#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo) -/** @ingroup netdbapi */ -#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_HDR_NETDB_H */ diff --git a/core/c/include/lwip/netif.h b/core/c/include/lwip/netif.h deleted file mode 100755 index d3ec064..0000000 --- a/core/c/include/lwip/netif.h +++ /dev/null @@ -1,669 +0,0 @@ -/** - * @file - * netif API (to be used from TCPIP thread) - */ - -/* - * 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_HDR_NETIF_H -#define LWIP_HDR_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" -#include "lwip/stats.h" - -#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. - This does not have to be changed, normally. */ -#ifndef NETIF_MAX_HWADDR_LEN -#define NETIF_MAX_HWADDR_LEN 6U -#endif - -/** The size of a fully constructed netif name which the - * netif can be identified by in APIs. Composed of - * 2 chars, 3 (max) digits, and 1 \0 - */ -#define NETIF_NAMESIZE 6 - -/** - * @defgroup netif_flags Flags - * @ingroup netif - * @{ - */ - -/** Whether the network interface is 'up'. This is - * a software flag used to control whether this network - * interface is enabled and processes traffic. - * It must be set by the startup code before this netif can be used - * (also for dhcp/autoip). - */ -#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 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 0x04U -/** 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 0x08U -/** 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 0x10U -/** If set, the netif has IGMP capability. - * Set by the netif driver in its init function. */ -#define NETIF_FLAG_IGMP 0x20U -/** If set, the netif has MLD6 capability. - * Set by the netif driver in its init function. */ -#define NETIF_FLAG_MLD6 0x40U - -/** - * @} - */ - -enum lwip_internal_netif_client_data_index -{ -#if LWIP_IPV4 -#if LWIP_DHCP - LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, -#endif -#if LWIP_AUTOIP - LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, -#endif -#if LWIP_IGMP - LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, -#endif -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 -#if LWIP_IPV6_DHCP6 - LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, -#endif -#if LWIP_IPV6_MLD - LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, -#endif -#endif /* LWIP_IPV6 */ - LWIP_NETIF_CLIENT_DATA_INDEX_MAX -}; - -#if LWIP_CHECKSUM_CTRL_PER_NETIF -#define NETIF_CHECKSUM_GEN_IP 0x0001 -#define NETIF_CHECKSUM_GEN_UDP 0x0002 -#define NETIF_CHECKSUM_GEN_TCP 0x0004 -#define NETIF_CHECKSUM_GEN_ICMP 0x0008 -#define NETIF_CHECKSUM_GEN_ICMP6 0x0010 -#define NETIF_CHECKSUM_CHECK_IP 0x0100 -#define NETIF_CHECKSUM_CHECK_UDP 0x0200 -#define NETIF_CHECKSUM_CHECK_TCP 0x0400 -#define NETIF_CHECKSUM_CHECK_ICMP 0x0800 -#define NETIF_CHECKSUM_CHECK_ICMP6 0x1000 -#define NETIF_CHECKSUM_ENABLE_ALL 0xFFFF -#define NETIF_CHECKSUM_DISABLE_ALL 0x0000 -#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ - -struct netif; - -/** MAC Filter Actions, these are passed to a netif's igmp_mac_filter or - * mld_mac_filter callback function. */ -enum netif_mac_filter_action { - /** Delete a filter entry */ - NETIF_DEL_MAC_FILTER = 0, - /** Add a filter entry */ - NETIF_ADD_MAC_FILTER = 1 -}; - -/** 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 - * @return ERR_OK if the packet was handled - * != ERR_OK is the packet was NOT handled, in this case, the caller has - * to free the pbuf - */ -typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp); - -#if LWIP_IPV4 -/** 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, - const ip4_addr_t *ipaddr); -#endif /* LWIP_IPV4*/ - -#if LWIP_IPV6 -/** Function prototype for netif->output_ip6 functions. Called by lwIP when a packet - * shall be sent. For ethernet netif, set this to 'ethip6_output' and set - * 'linkoutput'. - * - * @param netif The netif which shall send a packet - * @param p The packet to send (p->payload points to IP header) - * @param ipaddr The IPv6 address to which the packet shall be sent - */ -typedef err_t (*netif_output_ip6_fn)(struct netif *netif, struct pbuf *p, - const ip6_addr_t *ipaddr); -#endif /* LWIP_IPV6 */ - -/** Function prototype for netif->linkoutput functions. Only used for ethernet - * netifs. This function is called by ARP when a packet shall be sent. - * - * @param netif The netif which shall send a packet - * @param p The packet to send (raw ethernet packet) - */ -typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p); -/** Function prototype for netif status- or link-callback functions. */ -typedef void (*netif_status_callback_fn)(struct netif *netif); -#if LWIP_IPV4 && LWIP_IGMP -/** Function prototype for netif igmp_mac_filter functions */ -typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif, - const ip4_addr_t *group, enum netif_mac_filter_action action); -#endif /* LWIP_IPV4 && LWIP_IGMP */ -#if LWIP_IPV6 && LWIP_IPV6_MLD -/** Function prototype for netif mld_mac_filter functions */ -typedef err_t (*netif_mld_mac_filter_fn)(struct netif *netif, - const ip6_addr_t *group, enum netif_mac_filter_action action); -#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ - -#if LWIP_DHCP || LWIP_AUTOIP || LWIP_IGMP || LWIP_IPV6_MLD || LWIP_IPV6_DHCP6 || (LWIP_NUM_NETIF_CLIENT_DATA > 0) -#if LWIP_NUM_NETIF_CLIENT_DATA > 0 -u8_t netif_alloc_client_data_id(void); -#endif -/** @ingroup netif_cd - * Set client data. Obtain ID from netif_alloc_client_data_id(). - */ -#define netif_set_client_data(netif, id, data) netif_get_client_data(netif, id) = (data) -/** @ingroup netif_cd - * Get client data. Obtain ID from netif_alloc_client_data_id(). - */ -#define netif_get_client_data(netif, id) (netif)->client_data[(id)] -#endif - -#if (LWIP_IPV4 && LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) || (LWIP_IPV6 && (LWIP_ND6_NUM_DESTINATIONS > 0x7f)) -typedef u16_t netif_addr_idx_t; -#define NETIF_ADDR_IDX_MAX 0x7FFF -#else -typedef u8_t netif_addr_idx_t; -#define NETIF_ADDR_IDX_MAX 0x7F -#endif - -#if LWIP_NETIF_HWADDRHINT -#define LWIP_NETIF_USE_HINTS 1 -struct netif_hint { - netif_addr_idx_t addr_hint; -}; -#else /* LWIP_NETIF_HWADDRHINT */ -#define LWIP_NETIF_USE_HINTS 0 -#endif /* LWIP_NETIF_HWADDRHINT */ - -/** 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 { -#if !LWIP_SINGLE_NETIF - /** pointer to next in linked list */ - struct netif *next; -#endif - -#if LWIP_IPV4 - /** IP address configuration in network byte order */ - ip_addr_t ip_addr; - ip_addr_t netmask; - ip_addr_t gw; -#endif /* LWIP_IPV4 */ -#if LWIP_IPV6 - /** Array of IPv6 addresses for this netif. */ - ip_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES]; - /** The state of each IPv6 address (Tentative, Preferred, etc). - * @see ip6_addr.h */ - u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES]; -#if LWIP_IPV6_ADDRESS_LIFETIMES - /** Remaining valid and preferred lifetime of each IPv6 address, in seconds. - * For valid lifetimes, the special value of IP6_ADDR_LIFE_STATIC (0) - * indicates the address is static and has no lifetimes. */ - u32_t ip6_addr_valid_life[LWIP_IPV6_NUM_ADDRESSES]; - u32_t ip6_addr_pref_life[LWIP_IPV6_NUM_ADDRESSES]; -#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ -#endif /* LWIP_IPV6 */ - /** This function is called by the network device driver - * to pass a packet up the TCP/IP stack. */ - netif_input_fn input; -#if LWIP_IPV4 - /** 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. - * For ethernet physical layer, this is usually etharp_output() */ - netif_output_fn output; -#endif /* LWIP_IPV4 */ - /** This function is called by ethernet_output() 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_IPV6 - /** This function is called by the IPv6 module when it wants - * to send a packet on the interface. This function typically - * first resolves the hardware address, then sends the packet. - * For ethernet physical layer, this is usually ethip6_output() */ - netif_output_ip6_fn output_ip6; -#endif /* LWIP_IPV6 */ -#if LWIP_NETIF_STATUS_CALLBACK - /** This function is called when the netif state is set to up or down - */ - 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 */ -#if LWIP_NETIF_REMOVE_CALLBACK - /** This function is called when the netif has been removed */ - netif_status_callback_fn remove_callback; -#endif /* LWIP_NETIF_REMOVE_CALLBACK */ - /** This field can be set by the device driver and could point - * to state information for the device. */ - void *state; -#ifdef netif_get_client_data - void* client_data[LWIP_NETIF_CLIENT_DATA_INDEX_MAX + LWIP_NUM_NETIF_CLIENT_DATA]; -#endif -#if LWIP_NETIF_HOSTNAME - /* the hostname for this netif, NULL is a valid value */ - const char* hostname; -#endif /* LWIP_NETIF_HOSTNAME */ -#if LWIP_CHECKSUM_CTRL_PER_NETIF - u16_t chksum_flags; -#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/ - /** maximum transfer unit (in bytes) */ - u16_t mtu; -#if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES - /** maximum transfer unit (in bytes), updated by RA */ - u16_t mtu6; -#endif /* LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES */ - /** link level hardware address of this interface */ - u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; - /** number of bytes used in hwaddr */ - u8_t hwaddr_len; - /** flags (@see @ref netif_flags) */ - u8_t flags; - /** descriptive abbreviation */ - char name[2]; - /** number of this interface. Used for @ref if_api and @ref netifapi_netif, - * as well as for IPv6 zones */ - u8_t num; -#if LWIP_IPV6_AUTOCONFIG - /** is this netif enabled for IPv6 autoconfiguration */ - u8_t ip6_autoconfig_enabled; -#endif /* LWIP_IPV6_AUTOCONFIG */ -#if LWIP_IPV6_SEND_ROUTER_SOLICIT - /** Number of Router Solicitation messages that remain to be sent. */ - u8_t rs_count; -#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ -#if MIB2_STATS - /** link type (from "snmp_ifType" enum from snmp_mib2.h) */ - u8_t link_type; - /** (estimate) link speed */ - u32_t link_speed; - /** timestamp at last change made (up/down) */ - u32_t ts; - /** counters */ - struct stats_mib2_netif_ctrs mib2_counters; -#endif /* MIB2_STATS */ -#if LWIP_IPV4 && LWIP_IGMP - /** This function could be called to add or delete an entry in the multicast - filter table of the ethernet MAC.*/ - netif_igmp_mac_filter_fn igmp_mac_filter; -#endif /* LWIP_IPV4 && LWIP_IGMP */ -#if LWIP_IPV6 && LWIP_IPV6_MLD - /** This function could be called to add or delete an entry in the IPv6 multicast - filter table of the ethernet MAC. */ - netif_mld_mac_filter_fn mld_mac_filter; -#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ -#if LWIP_NETIF_USE_HINTS - struct netif_hint *hints; -#endif /* LWIP_NETIF_USE_HINTS */ -#if ENABLE_LOOPBACK - /* List of packets to be queued for ourselves. */ - struct pbuf *loop_first; - struct pbuf *loop_last; -#if LWIP_LOOPBACK_MAX_PBUFS - u16_t loop_cnt_current; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ -#endif /* ENABLE_LOOPBACK */ -}; - -#if LWIP_CHECKSUM_CTRL_PER_NETIF -#define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) do { \ - (netif)->chksum_flags = chksumflags; } while(0) -#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) if (((netif) == NULL) || (((netif)->chksum_flags & (chksumflag)) != 0)) -#else /* LWIP_CHECKSUM_CTRL_PER_NETIF */ -#define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) -#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) -#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ - -#if LWIP_SINGLE_NETIF -#define NETIF_FOREACH(netif) if (((netif) = netif_default) != NULL) -#else /* LWIP_SINGLE_NETIF */ -/** The list of network interfaces. */ -extern struct netif *netif_list; -#define NETIF_FOREACH(netif) for ((netif) = netif_list; (netif) != NULL; (netif) = (netif)->next) -#endif /* LWIP_SINGLE_NETIF */ -/** The default network interface. */ -extern struct netif *netif_default; - -void netif_init(void); - -struct netif *netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input); - -#if LWIP_IPV4 -struct netif *netif_add(struct netif *netif, - const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, - void *state, netif_init_fn init, netif_input_fn input); -void netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, - const ip4_addr_t *gw); -#else /* LWIP_IPV4 */ -struct netif *netif_add(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input); -#endif /* LWIP_IPV4 */ -void netif_remove(struct netif * netif); - -/* 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(const char *name); - -void netif_set_default(struct netif *netif); - -#if LWIP_IPV4 -void netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr); -void netif_set_netmask(struct netif *netif, const ip4_addr_t *netmask); -void netif_set_gw(struct netif *netif, const ip4_addr_t *gw); -/** @ingroup netif_ip4 */ -#define netif_ip4_addr(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->ip_addr))) -/** @ingroup netif_ip4 */ -#define netif_ip4_netmask(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->netmask))) -/** @ingroup netif_ip4 */ -#define netif_ip4_gw(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->gw))) -/** @ingroup netif_ip4 */ -#define netif_ip_addr4(netif) ((const ip_addr_t*)&((netif)->ip_addr)) -/** @ingroup netif_ip4 */ -#define netif_ip_netmask4(netif) ((const ip_addr_t*)&((netif)->netmask)) -/** @ingroup netif_ip4 */ -#define netif_ip_gw4(netif) ((const ip_addr_t*)&((netif)->gw)) -#endif /* LWIP_IPV4 */ - -#define netif_set_flags(netif, set_flags) do { (netif)->flags = (u8_t)((netif)->flags | (set_flags)); } while(0) -#define netif_clear_flags(netif, clr_flags) do { (netif)->flags = (u8_t)((netif)->flags & (u8_t)(~(clr_flags) & 0xff)); } while(0) -#define netif_is_flag_set(nefif, flag) (((netif)->flags & (flag)) != 0) - -void netif_set_up(struct netif *netif); -void netif_set_down(struct netif *netif); -/** @ingroup netif - * Ask if an interface is up - */ -#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0) - -#if LWIP_NETIF_STATUS_CALLBACK -void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback); -#endif /* LWIP_NETIF_STATUS_CALLBACK */ -#if LWIP_NETIF_REMOVE_CALLBACK -void netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback); -#endif /* LWIP_NETIF_REMOVE_CALLBACK */ - -void netif_set_link_up(struct netif *netif); -void netif_set_link_down(struct netif *netif); -/** Ask if a link is up */ -#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0) - -#if LWIP_NETIF_LINK_CALLBACK -void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback); -#endif /* LWIP_NETIF_LINK_CALLBACK */ - -#if LWIP_NETIF_HOSTNAME -/** @ingroup netif */ -#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0) -/** @ingroup netif */ -#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL) -#endif /* LWIP_NETIF_HOSTNAME */ - -#if LWIP_IGMP -/** @ingroup netif */ -#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 LWIP_IPV6 && LWIP_IPV6_MLD -/** @ingroup netif */ -#define netif_set_mld_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->mld_mac_filter = function; }}while(0) -#define netif_get_mld_mac_filter(netif) (((netif) != NULL) ? ((netif)->mld_mac_filter) : NULL) -#define netif_mld_mac_filter(netif, addr, action) do { if((netif) && (netif)->mld_mac_filter) { (netif)->mld_mac_filter((netif), (addr), (action)); }}while(0) -#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ - -#if ENABLE_LOOPBACK -err_t netif_loop_output(struct netif *netif, struct pbuf *p); -void netif_poll(struct netif *netif); -#if !LWIP_NETIF_LOOPBACK_MULTITHREADING -void netif_poll_all(void); -#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ -#endif /* ENABLE_LOOPBACK */ - -err_t netif_input(struct pbuf *p, struct netif *inp); - -#if LWIP_IPV6 -/** @ingroup netif_ip6 */ -#define netif_ip_addr6(netif, i) ((const ip_addr_t*)(&((netif)->ip6_addr[i]))) -/** @ingroup netif_ip6 */ -#define netif_ip6_addr(netif, i) ((const ip6_addr_t*)ip_2_ip6(&((netif)->ip6_addr[i]))) -void netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, const ip6_addr_t *addr6); -void netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, u32_t i2, u32_t i3); -#define netif_ip6_addr_state(netif, i) ((netif)->ip6_addr_state[i]) -void netif_ip6_addr_set_state(struct netif* netif, s8_t addr_idx, u8_t state); -s8_t netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr); -void netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit); -err_t netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx); -#define netif_set_ip6_autoconfig_enabled(netif, action) do { if(netif) { (netif)->ip6_autoconfig_enabled = (action); }}while(0) -#if LWIP_IPV6_ADDRESS_LIFETIMES -#define netif_ip6_addr_valid_life(netif, i) \ - (((netif) != NULL) ? ((netif)->ip6_addr_valid_life[i]) : IP6_ADDR_LIFE_STATIC) -#define netif_ip6_addr_set_valid_life(netif, i, secs) \ - do { if (netif != NULL) { (netif)->ip6_addr_valid_life[i] = (secs); }} while (0) -#define netif_ip6_addr_pref_life(netif, i) \ - (((netif) != NULL) ? ((netif)->ip6_addr_pref_life[i]) : IP6_ADDR_LIFE_STATIC) -#define netif_ip6_addr_set_pref_life(netif, i, secs) \ - do { if (netif != NULL) { (netif)->ip6_addr_pref_life[i] = (secs); }} while (0) -#define netif_ip6_addr_isstatic(netif, i) \ - (netif_ip6_addr_valid_life((netif), (i)) == IP6_ADDR_LIFE_STATIC) -#else /* !LWIP_IPV6_ADDRESS_LIFETIMES */ -#define netif_ip6_addr_isstatic(netif, i) (1) /* all addresses are static */ -#endif /* !LWIP_IPV6_ADDRESS_LIFETIMES */ -#if LWIP_ND6_ALLOW_RA_UPDATES -#define netif_mtu6(netif) ((netif)->mtu6) -#else /* LWIP_ND6_ALLOW_RA_UPDATES */ -#define netif_mtu6(netif) ((netif)->mtu) -#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ -#endif /* LWIP_IPV6 */ - -#if LWIP_NETIF_USE_HINTS -#define NETIF_SET_HINTS(netif, netifhint) (netif)->hints = (netifhint) -#define NETIF_RESET_HINTS(netif) (netif)->hints = NULL -#else /* LWIP_NETIF_USE_HINTS */ -#define NETIF_SET_HINTS(netif, netifhint) -#define NETIF_RESET_HINTS(netif) -#endif /* LWIP_NETIF_USE_HINTS */ - -u8_t netif_name_to_index(const char *name); -char * netif_index_to_name(u8_t idx, char *name); -struct netif* netif_get_by_index(u8_t idx); - -/* Interface indexes always start at 1 per RFC 3493, section 4, num starts at 0 (internal index is 0..254)*/ -#define netif_get_index(netif) ((u8_t)((netif)->num + 1)) -#define NETIF_NO_INDEX (0) - -/** - * @ingroup netif - * Extended netif status callback (NSC) reasons flags. - * May be extended in the future! - */ -typedef u16_t netif_nsc_reason_t; - -/* used for initialization only */ -#define LWIP_NSC_NONE 0x0000 -/** netif was added. arg: NULL. Called AFTER netif was added. */ -#define LWIP_NSC_NETIF_ADDED 0x0001 -/** netif was removed. arg: NULL. Called BEFORE netif is removed. */ -#define LWIP_NSC_NETIF_REMOVED 0x0002 -/** link changed */ -#define LWIP_NSC_LINK_CHANGED 0x0004 -/** netif administrative status changed.\n - * up is called AFTER netif is set up.\n - * down is called BEFORE the netif is actually set down. */ -#define LWIP_NSC_STATUS_CHANGED 0x0008 -/** IPv4 address has changed */ -#define LWIP_NSC_IPV4_ADDRESS_CHANGED 0x0010 -/** IPv4 gateway has changed */ -#define LWIP_NSC_IPV4_GATEWAY_CHANGED 0x0020 -/** IPv4 netmask has changed */ -#define LWIP_NSC_IPV4_NETMASK_CHANGED 0x0040 -/** called AFTER IPv4 address/gateway/netmask changes have been applied */ -#define LWIP_NSC_IPV4_SETTINGS_CHANGED 0x0080 -/** IPv6 address was added */ -#define LWIP_NSC_IPV6_SET 0x0100 -/** IPv6 address state has changed */ -#define LWIP_NSC_IPV6_ADDR_STATE_CHANGED 0x0200 - -/** @ingroup netif - * Argument supplied to netif_ext_callback_fn. - */ -typedef union -{ - /** Args to LWIP_NSC_LINK_CHANGED callback */ - struct link_changed_s - { - /** 1: up; 0: down */ - u8_t state; - } link_changed; - /** Args to LWIP_NSC_STATUS_CHANGED callback */ - struct status_changed_s - { - /** 1: up; 0: down */ - u8_t state; - } status_changed; - /** Args to LWIP_NSC_IPV4_ADDRESS_CHANGED|LWIP_NSC_IPV4_GATEWAY_CHANGED|LWIP_NSC_IPV4_NETMASK_CHANGED|LWIP_NSC_IPV4_SETTINGS_CHANGED callback */ - struct ipv4_changed_s - { - /** Old IPv4 address */ - const ip_addr_t* old_address; - const ip_addr_t* old_netmask; - const ip_addr_t* old_gw; - } ipv4_changed; - /** Args to LWIP_NSC_IPV6_SET callback */ - struct ipv6_set_s - { - /** Index of changed IPv6 address */ - s8_t addr_index; - /** Old IPv6 address */ - const ip_addr_t* old_address; - } ipv6_set; - /** Args to LWIP_NSC_IPV6_ADDR_STATE_CHANGED callback */ - struct ipv6_addr_state_changed_s - { - /** Index of affected IPv6 address */ - s8_t addr_index; - /** Old IPv6 address state */ - u8_t old_state; - /** Affected IPv6 address */ - const ip_addr_t* address; - } ipv6_addr_state_changed; -} netif_ext_callback_args_t; - -/** - * @ingroup netif - * Function used for extended netif status callbacks - * Note: When parsing reason argument, keep in mind that more reasons may be added in the future! - * @param netif netif that is affected by change - * @param reason change reason - * @param args depends on reason, see reason description - */ -typedef void (*netif_ext_callback_fn)(struct netif* netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t* args); - -#if LWIP_NETIF_EXT_STATUS_CALLBACK -struct netif_ext_callback; -typedef struct netif_ext_callback -{ - netif_ext_callback_fn callback_fn; - struct netif_ext_callback* next; -} netif_ext_callback_t; - -#define NETIF_DECLARE_EXT_CALLBACK(name) static netif_ext_callback_t name; -void netif_add_ext_callback(netif_ext_callback_t* callback, netif_ext_callback_fn fn); -void netif_remove_ext_callback(netif_ext_callback_t* callback); -void netif_invoke_ext_callback(struct netif* netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t* args); -#else -#define NETIF_DECLARE_EXT_CALLBACK(name) -#define netif_add_ext_callback(callback, fn) -#define netif_remove_ext_callback(callback) -#define netif_invoke_ext_callback(netif, reason, args) -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_NETIF_H */ diff --git a/core/c/include/lwip/netifapi.h b/core/c/include/lwip/netifapi.h deleted file mode 100755 index 5bbd8f8..0000000 --- a/core/c/include/lwip/netifapi.h +++ /dev/null @@ -1,161 +0,0 @@ -/** - * @file - * netif API (to be used from non-TCPIP threads) - */ - -/* - * 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_HDR_NETIFAPI_H -#define LWIP_HDR_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" -#include "lwip/priv/tcpip_priv.h" -#include "lwip/priv/api_msg.h" -#include "lwip/prot/ethernet.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* API for application */ -#if LWIP_ARP && LWIP_IPV4 -/* Used for netfiapi_arp_* APIs */ -enum netifapi_arp_entry { - NETIFAPI_ARP_PERM /* Permanent entry */ - /* Other entry types can be added here */ -}; - -/** @ingroup netifapi_arp */ -err_t netifapi_arp_add(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr, enum netifapi_arp_entry type); -/** @ingroup netifapi_arp */ -err_t netifapi_arp_remove(const ip4_addr_t *ipaddr, enum netifapi_arp_entry type); -#endif /* LWIP_ARP && LWIP_IPV4 */ - -err_t netifapi_netif_add(struct netif *netif, -#if LWIP_IPV4 - const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, -#endif /* LWIP_IPV4 */ - void *state, netif_init_fn init, netif_input_fn input); - -#if LWIP_IPV4 -err_t netifapi_netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, - const ip4_addr_t *netmask, const ip4_addr_t *gw); -#endif /* LWIP_IPV4*/ - -err_t netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, - netifapi_errt_fn errtfunc); - -/** @ingroup netifapi_netif */ -err_t netifapi_netif_name_to_index(const char *name, u8_t *index); -/** @ingroup netifapi_netif */ -err_t netifapi_netif_index_to_name(u8_t index, char *name); - -/** @ingroup netifapi_netif - * @see netif_remove() - */ -#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) -/** @ingroup netifapi_netif - * @see netif_set_up() - */ -#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) -/** @ingroup netifapi_netif - * @see netif_set_down() - */ -#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL) -/** @ingroup netifapi_netif - * @see netif_set_default() - */ -#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) -/** @ingroup netifapi_netif - * @see netif_set_link_up() - */ -#define netifapi_netif_set_link_up(n) netifapi_netif_common(n, netif_set_link_up, NULL) -/** @ingroup netifapi_netif - * @see netif_set_link_down() - */ -#define netifapi_netif_set_link_down(n) netifapi_netif_common(n, netif_set_link_down, NULL) - -/** - * @defgroup netifapi_dhcp4 DHCPv4 - * @ingroup netifapi - * To be called from non-TCPIP threads - */ -/** @ingroup netifapi_dhcp4 - * @see dhcp_start() - */ -#define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start) -/** - * @ingroup netifapi_dhcp4 - * @deprecated Use netifapi_dhcp_release_and_stop() instead. - */ -#define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL) -/** @ingroup netifapi_dhcp4 - * @see dhcp_inform() - */ -#define netifapi_dhcp_inform(n) netifapi_netif_common(n, dhcp_inform, NULL) -/** @ingroup netifapi_dhcp4 - * @see dhcp_renew() - */ -#define netifapi_dhcp_renew(n) netifapi_netif_common(n, NULL, dhcp_renew) -/** - * @ingroup netifapi_dhcp4 - * @deprecated Use netifapi_dhcp_release_and_stop() instead. - */ -#define netifapi_dhcp_release(n) netifapi_netif_common(n, NULL, dhcp_release) -/** @ingroup netifapi_dhcp4 - * @see dhcp_release_and_stop() - */ -#define netifapi_dhcp_release_and_stop(n) netifapi_netif_common(n, dhcp_release_and_stop, NULL) - -/** - * @defgroup netifapi_autoip AUTOIP - * @ingroup netifapi - * To be called from non-TCPIP threads - */ -/** @ingroup netifapi_autoip - * @see autoip_start() - */ -#define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start) -/** @ingroup netifapi_autoip - * @see autoip_stop() - */ -#define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_NETIF_API */ - -#endif /* LWIP_HDR_NETIFAPI_H */ diff --git a/core/c/include/lwip/opt.h b/core/c/include/lwip/opt.h deleted file mode 100755 index bb6c33d..0000000 --- a/core/c/include/lwip/opt.h +++ /dev/null @@ -1,3519 +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 - * - */ - -/* - * NOTE: || defined __DOXYGEN__ is a workaround for doxygen bug - - * without this, doxygen does not see the actual #define - */ - -#if !defined LWIP_HDR_OPT_H -#define LWIP_HDR_OPT_H - -/* - * Include user defined options first. Anything not defined in these files - * will be set to standard values. Override anything you don't like! - */ -#include "lwipopts.h" -#include "lwip/debug.h" - -/** - * @defgroup lwip_opts Options (lwipopts.h) - * @ingroup lwip - * - * @defgroup lwip_opts_debug Debugging - * @ingroup lwip_opts - * - * @defgroup lwip_opts_infrastructure Infrastructure - * @ingroup lwip_opts - * - * @defgroup lwip_opts_callback Callback-style APIs - * @ingroup lwip_opts - * - * @defgroup lwip_opts_threadsafe_apis Thread-safe APIs - * @ingroup lwip_opts - */ - - /* - ------------------------------------ - -------------- NO SYS -------------- - ------------------------------------ -*/ -/** - * @defgroup lwip_opts_nosys NO_SYS - * @ingroup lwip_opts_infrastructure - * @{ - */ -/** - * NO_SYS==1: Use lwIP without OS-awareness (no thread, semaphores, mutexes or - * mboxes). This means threaded APIs cannot be used (socket, netconn, - * i.e. everything in the 'api' folder), only the callback-style raw API is - * available (and you have to watch out for yourself that you don't access - * lwIP functions/structures from more than one context at a time!) - */ -#if !defined NO_SYS || defined __DOXYGEN__ -#define NO_SYS 0 -#endif -/** - * @} - */ - -/** - * @defgroup lwip_opts_timers Timers - * @ingroup lwip_opts_infrastructure - * @{ - */ -/** - * LWIP_TIMERS==0: Drop support for sys_timeout and lwip-internal cyclic timers. - * (the array of lwip-internal cyclic timers is still provided) - * (check NO_SYS_NO_TIMERS for compatibility to old versions) - */ -#if !defined LWIP_TIMERS || defined __DOXYGEN__ -#ifdef NO_SYS_NO_TIMERS -#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) -#else -#define LWIP_TIMERS 1 -#endif -#endif - -/** - * LWIP_TIMERS_CUSTOM==1: Provide your own timer implementation. - * Function prototypes in timeouts.h and the array of lwip-internal cyclic timers - * are still included, but the implementation is not. The following functions - * will be required: sys_timeouts_init(), sys_timeout(), sys_untimeout(), - * sys_timeouts_mbox_fetch() - */ -#if !defined LWIP_TIMERS_CUSTOM || defined __DOXYGEN__ -#define LWIP_TIMERS_CUSTOM 0 -#endif -/** - * @} - */ - -/** - * @defgroup lwip_opts_memcpy memcpy - * @ingroup lwip_opts_infrastructure - * @{ - */ -/** - * MEMCPY: override this if you have a faster implementation at hand than the - * one included in your C library - */ -#if !defined MEMCPY || defined __DOXYGEN__ -#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. - */ -#if !defined SMEMCPY || defined __DOXYGEN__ -#define SMEMCPY(dst,src,len) memcpy(dst,src,len) -#endif - -/** - * MEMMOVE: override this if you have a faster implementation at hand than the - * one included in your C library. lwIP currently uses MEMMOVE only when IPv6 - * fragmentation support is enabled. - */ -#if !defined MEMMOVE || defined __DOXYGEN__ -#define MEMMOVE(dst,src,len) memmove(dst,src,len) -#endif -/** - * @} - */ - -/* - ------------------------------------ - ----------- Core locking ----------- - ------------------------------------ -*/ -/** - * @defgroup lwip_opts_lock Core locking and MPU - * @ingroup lwip_opts_infrastructure - * @{ - */ -/** - * LWIP_MPU_COMPATIBLE: enables special memory management mechanism - * which makes lwip able to work on MPU (Memory Protection Unit) system - * by not passing stack-pointers to other threads - * (this decreases performance as memory is allocated from pools instead - * of keeping it on the stack) - */ -#if !defined LWIP_MPU_COMPATIBLE || defined __DOXYGEN__ -#define LWIP_MPU_COMPATIBLE 0 -#endif - -/** - * LWIP_TCPIP_CORE_LOCKING - * Creates a global mutex that is held during TCPIP thread operations. - * Can be locked by client code to perform lwIP operations without changing - * into TCPIP thread using callbacks. See LOCK_TCPIP_CORE() and - * UNLOCK_TCPIP_CORE(). - * Your system should provide mutexes supporting priority inversion to use this. - */ -#if !defined LWIP_TCPIP_CORE_LOCKING || defined __DOXYGEN__ -#define LWIP_TCPIP_CORE_LOCKING 1 -#endif - -/** - * LWIP_TCPIP_CORE_LOCKING_INPUT: when LWIP_TCPIP_CORE_LOCKING is enabled, - * this lets tcpip_input() grab the mutex for input packets as well, - * instead of allocating a message and passing it to tcpip_thread. - * - * ATTENTION: this does not work when tcpip_input() is called from - * interrupt context! - */ -#if !defined LWIP_TCPIP_CORE_LOCKING_INPUT || defined __DOXYGEN__ -#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 -#endif - -/** - * SYS_LIGHTWEIGHT_PROT==1: enable inter-task protection (and task-vs-interrupt - * protection) for certain critical regions during buffer allocation, deallocation - * and memory allocation and deallocation. - * ATTENTION: This is required when using lwIP from more than one context! If - * you disable this, you must be sure what you are doing! - */ -#if !defined SYS_LIGHTWEIGHT_PROT || defined __DOXYGEN__ -#define SYS_LIGHTWEIGHT_PROT 1 -#endif - -/** - * Macro/function to check whether lwIP's threading/locking - * requirements are satisfied during current function call. - * This macro usually calls a function that is implemented in the OS-dependent - * sys layer and performs the following checks: - * - Not in ISR (this should be checked for NO_SYS==1, too!) - * - If @ref LWIP_TCPIP_CORE_LOCKING = 1: TCPIP core lock is held - * - If @ref LWIP_TCPIP_CORE_LOCKING = 0: function is called from TCPIP thread - * @see @ref multithreading - */ -#if !defined LWIP_ASSERT_CORE_LOCKED || defined __DOXYGEN__ -#define LWIP_ASSERT_CORE_LOCKED() -#endif - -/** - * Called as first thing in the lwIP TCPIP thread. Can be used in conjunction - * with @ref LWIP_ASSERT_CORE_LOCKED to check core locking. - * @see @ref multithreading - */ -#if !defined LWIP_MARK_TCPIP_THREAD || defined __DOXYGEN__ -#define LWIP_MARK_TCPIP_THREAD() -#endif -/** - * @} - */ - -/* - ------------------------------------ - ---------- Memory options ---------- - ------------------------------------ -*/ -/** - * @defgroup lwip_opts_mem Heap and memory pools - * @ingroup lwip_opts_infrastructure - * @{ - */ -/** - * 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. - */ -#if !defined MEM_LIBC_MALLOC || defined __DOXYGEN__ -#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 (heap alloc can be much slower than pool alloc) and usage from interrupts - * (especially if your netif driver allocates PBUF_POOL pbufs for received frames - * from interrupt)! - * ATTENTION: Currently, this uses the heap for ALL pools (also for private pools, - * not only for internal pools defined in memp_std.h)! - */ -#if !defined MEMP_MEM_MALLOC || defined __DOXYGEN__ -#define MEMP_MEM_MALLOC 0 -#endif - -/** - * MEMP_MEM_INIT==1: Force use of memset to initialize pool memory. - * Useful if pool are moved in uninitialized section of memory. This will ensure - * default values in pcbs struct are well initialized in all conditions. - */ -#if !defined MEMP_MEM_INIT || defined __DOXYGEN__ -#define MEMP_MEM_INIT 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 - */ -#if !defined MEM_ALIGNMENT || defined __DOXYGEN__ -#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. - */ -#if !defined MEM_SIZE || defined __DOXYGEN__ -#define MEM_SIZE 1600 -#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!) - */ -#if !defined MEMP_OVERFLOW_CHECK || defined __DOXYGEN__ -#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. - */ -#if !defined MEMP_SANITY_CHECK || defined __DOXYGEN__ -#define MEMP_SANITY_CHECK 0 -#endif - -/** - * MEM_OVERFLOW_CHECK: mem overflow protection reserves a configurable - * amount of bytes before and after each heap allocation chunk and fills - * it with a prominent default value. - * MEM_OVERFLOW_CHECK == 0 no checking - * MEM_OVERFLOW_CHECK == 1 checks each element when it is freed - * MEM_OVERFLOW_CHECK >= 2 checks all heap elements every time - * mem_malloc() or mem_free() is called (useful but slow!) - */ -#if !defined MEM_OVERFLOW_CHECK || defined __DOXYGEN__ -#define MEM_OVERFLOW_CHECK 0 -#endif - -/** - * MEM_SANITY_CHECK==1: run a sanity check after each mem_free() to make - * sure that the linked list of heap elements is not corrupted. - */ -#if !defined MEM_SANITY_CHECK || defined __DOXYGEN__ -#define MEM_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. - */ -#if !defined MEM_USE_POOLS || defined __DOXYGEN__ -#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. */ -#if !defined MEM_USE_POOLS_TRY_BIGGER_POOL || defined __DOXYGEN__ -#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 - * include path somewhere. - */ -#if !defined MEMP_USE_CUSTOM_POOLS || defined __DOXYGEN__ -#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); - */ -#if !defined LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT || defined __DOXYGEN__ -#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 -#endif -/** - * @} - */ - -/* - ------------------------------------------------ - ---------- Internal Memory Pool Sizes ---------- - ------------------------------------------------ -*/ -/** - * @defgroup lwip_opts_memp Internal memory pools - * @ingroup lwip_opts_infrastructure - * @{ - */ -/** - * 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. - */ -#if !defined MEMP_NUM_PBUF || defined __DOXYGEN__ -#define MEMP_NUM_PBUF 16 -#endif - -/** - * MEMP_NUM_RAW_PCB: Number of raw connection PCBs - * (requires the LWIP_RAW option) - */ -#if !defined MEMP_NUM_RAW_PCB || defined __DOXYGEN__ -#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) - */ -#if !defined MEMP_NUM_UDP_PCB || defined __DOXYGEN__ -#define MEMP_NUM_UDP_PCB 4 -#endif - -/** - * MEMP_NUM_TCP_PCB: the number of simultaneously active TCP connections. - * (requires the LWIP_TCP option) - */ -#if !defined MEMP_NUM_TCP_PCB || defined __DOXYGEN__ -#define MEMP_NUM_TCP_PCB 5 -#endif - -/** - * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. - * (requires the LWIP_TCP option) - */ -#if !defined MEMP_NUM_TCP_PCB_LISTEN || defined __DOXYGEN__ -#define MEMP_NUM_TCP_PCB_LISTEN 8 -#endif - -/** - * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. - * (requires the LWIP_TCP option) - */ -#if !defined MEMP_NUM_TCP_SEG || defined __DOXYGEN__ -#define MEMP_NUM_TCP_SEG 16 -#endif - -/** - * MEMP_NUM_ALTCP_PCB: the number of simultaneously active altcp layer pcbs. - * (requires the LWIP_ALTCP option) - * Connections with multiple layers require more than one altcp_pcb (e.g. TLS - * over TCP requires 2 altcp_pcbs, one for TLS and one for TCP). - */ -#if !defined MEMP_NUM_ALTCP_PCB || defined __DOXYGEN__ -#define MEMP_NUM_ALTCP_PCB MEMP_NUM_TCP_PCB -#endif - -/** - * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for - * reassembly (whole packets, not fragments!) - */ -#if !defined MEMP_NUM_REASSDATA || defined __DOXYGEN__ -#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 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. - */ -#if !defined MEMP_NUM_FRAG_PBUF || defined __DOXYGEN__ -#define MEMP_NUM_FRAG_PBUF 15 -#endif - -/** - * MEMP_NUM_ARP_QUEUE: the number of simultaneously queued outgoing - * packets (pbufs) that are waiting for an ARP request (to resolve - * their destination address) to finish. - * (requires the ARP_QUEUEING option) - */ -#if !defined MEMP_NUM_ARP_QUEUE || defined __DOXYGEN__ -#define MEMP_NUM_ARP_QUEUE 30 -#endif - -/** - * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces - * can be members at the same time (one per netif - allsystems group -, plus one - * per netif membership). - * (requires the LWIP_IGMP option) - */ -#if !defined MEMP_NUM_IGMP_GROUP || defined __DOXYGEN__ -#define MEMP_NUM_IGMP_GROUP 8 -#endif - -/** - * The number of sys timeouts used by the core stack (not apps) - * The default number of timeouts is calculated here for all enabled modules. - */ -#define LWIP_NUM_SYS_TIMEOUT_INTERNAL (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_NUM_TIMEOUTS + (LWIP_IPV6 * (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD))) - -/** - * MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active timeouts. - * The default number of timeouts is calculated here for all enabled modules. - * The formula expects settings to be either '0' or '1'. - */ -#if !defined MEMP_NUM_SYS_TIMEOUT || defined __DOXYGEN__ -#define MEMP_NUM_SYS_TIMEOUT LWIP_NUM_SYS_TIMEOUT_INTERNAL -#endif - -/** - * MEMP_NUM_NETBUF: the number of struct netbufs. - * (only needed if you use the sequential API, like api_lib.c) - */ -#if !defined MEMP_NUM_NETBUF || defined __DOXYGEN__ -#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) - */ -#if !defined MEMP_NUM_NETCONN || defined __DOXYGEN__ -#define MEMP_NUM_NETCONN 4 -#endif - -/** - * MEMP_NUM_SELECT_CB: the number of struct lwip_select_cb. - * (Only needed if you have LWIP_MPU_COMPATIBLE==1 and use the socket API. - * In that case, you need one per thread calling lwip_select.) - */ -#if !defined MEMP_NUM_SELECT_CB || defined __DOXYGEN__ -#define MEMP_NUM_SELECT_CB 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) - */ -#if !defined MEMP_NUM_TCPIP_MSG_API || defined __DOXYGEN__ -#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) - */ -#if !defined MEMP_NUM_TCPIP_MSG_INPKT || defined __DOXYGEN__ -#define MEMP_NUM_TCPIP_MSG_INPKT 8 -#endif - -/** - * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls - * (before freeing the corresponding memory using lwip_freeaddrinfo()). - */ -#if !defined MEMP_NUM_NETDB || defined __DOXYGEN__ -#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. - */ -#if !defined MEMP_NUM_LOCALHOSTLIST || defined __DOXYGEN__ -#define MEMP_NUM_LOCALHOSTLIST 1 -#endif - -/** - * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. - */ -#if !defined PBUF_POOL_SIZE || defined __DOXYGEN__ -#define PBUF_POOL_SIZE 16 -#endif - -/** MEMP_NUM_API_MSG: the number of concurrently active calls to various - * socket, netconn, and tcpip functions - */ -#if !defined MEMP_NUM_API_MSG || defined __DOXYGEN__ -#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API -#endif - -/** MEMP_NUM_DNS_API_MSG: the number of concurrently active calls to netconn_gethostbyname - */ -#if !defined MEMP_NUM_DNS_API_MSG || defined __DOXYGEN__ -#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API -#endif - -/** MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA: the number of concurrently active calls - * to getsockopt/setsockopt - */ -#if !defined MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA || defined __DOXYGEN__ -#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API -#endif - -/** MEMP_NUM_NETIFAPI_MSG: the number of concurrently active calls to the - * netifapi functions - */ -#if !defined MEMP_NUM_NETIFAPI_MSG || defined __DOXYGEN__ -#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API -#endif -/** - * @} - */ - -/* - --------------------------------- - ---------- ARP options ---------- - --------------------------------- -*/ -/** - * @defgroup lwip_opts_arp ARP - * @ingroup lwip_opts_ipv4 - * @{ - */ -/** - * LWIP_ARP==1: Enable ARP functionality. - */ -#if !defined LWIP_ARP || defined __DOXYGEN__ -#define LWIP_ARP 1 -#endif - -/** - * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. - */ -#if !defined ARP_TABLE_SIZE || defined __DOXYGEN__ -#define ARP_TABLE_SIZE 10 -#endif - -/** the time an ARP entry stays valid after its last update, - * for ARP_TMR_INTERVAL = 1000, this is - * (60 * 5) seconds = 5 minutes. - */ -#if !defined ARP_MAXAGE || defined __DOXYGEN__ -#define ARP_MAXAGE 300 -#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. - */ -#if !defined ARP_QUEUEING || defined __DOXYGEN__ -#define ARP_QUEUEING 0 -#endif - -/** The maximum number of packets which may be queued for each - * unresolved address by other network layers. Defaults to 3, 0 means disabled. - * Old packets are dropped, new packets are queued. - */ -#if !defined ARP_QUEUE_LEN || defined __DOXYGEN__ -#define ARP_QUEUE_LEN 3 -#endif - -/** - * ETHARP_SUPPORT_VLAN==1: support receiving and sending ethernet packets with - * VLAN header. See the description of LWIP_HOOK_VLAN_CHECK and - * LWIP_HOOK_VLAN_SET hooks to check/set VLAN headers. - * 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. - * Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan) - * that returns 1 to accept a packet or 0 to drop a packet. - */ -#if !defined ETHARP_SUPPORT_VLAN || defined __DOXYGEN__ -#define ETHARP_SUPPORT_VLAN 0 -#endif - -/** LWIP_ETHERNET==1: enable ethernet support even though ARP might be disabled - */ -#if !defined LWIP_ETHERNET || defined __DOXYGEN__ -#define LWIP_ETHERNET LWIP_ARP -#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. - */ -#if !defined ETH_PAD_SIZE || defined __DOXYGEN__ -#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). - */ -#if !defined ETHARP_SUPPORT_STATIC_ENTRIES || defined __DOXYGEN__ -#define ETHARP_SUPPORT_STATIC_ENTRIES 0 -#endif - -/** ETHARP_TABLE_MATCH_NETIF==1: Match netif for ARP table entries. - * If disabled, duplicate IP address on multiple netifs are not supported - * (but this should only occur for AutoIP). - */ -#if !defined ETHARP_TABLE_MATCH_NETIF || defined __DOXYGEN__ -#define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF -#endif -/** - * @} - */ - -/* - -------------------------------- - ---------- IP options ---------- - -------------------------------- -*/ -/** - * @defgroup lwip_opts_ipv4 IPv4 - * @ingroup lwip_opts - * @{ - */ -/** - * LWIP_IPV4==1: Enable IPv4 - */ -#if !defined LWIP_IPV4 || defined __DOXYGEN__ -#define LWIP_IPV4 1 -#endif - -/** - * 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. - */ -#if !defined IP_FORWARD || defined __DOXYGEN__ -#define IP_FORWARD 0 -#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. - */ -#if !defined IP_REASSEMBLY || defined __DOXYGEN__ -#define IP_REASSEMBLY 1 -#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. - */ -#if !defined IP_FRAG || defined __DOXYGEN__ -#define IP_FRAG 1 -#endif - -#if !LWIP_IPV4 -/* disable IPv4 extensions when IPv4 is disabled */ -#undef IP_FORWARD -#define IP_FORWARD 0 -#undef IP_REASSEMBLY -#define IP_REASSEMBLY 0 -#undef IP_FRAG -#define IP_FRAG 0 -#endif /* !LWIP_IPV4 */ - -/** - * 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). - */ -#if !defined IP_OPTIONS_ALLOWED || defined __DOXYGEN__ -#define IP_OPTIONS_ALLOWED 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. - */ -#if !defined IP_REASS_MAXAGE || defined __DOXYGEN__ -#define IP_REASS_MAXAGE 15 -#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! - * When IPv4 *and* IPv6 are enabled, this even changes to - * (PBUF_POOL_SIZE > 2 * IP_REASS_MAX_PBUFS)! - */ -#if !defined IP_REASS_MAX_PBUFS || defined __DOXYGEN__ -#define IP_REASS_MAX_PBUFS 10 -#endif - -/** - * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. - */ -#if !defined IP_DEFAULT_TTL || defined __DOXYGEN__ -#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. - */ -#if !defined IP_SOF_BROADCAST || defined __DOXYGEN__ -#define IP_SOF_BROADCAST 0 -#endif - -/** - * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast - * filter on recv operations. - */ -#if !defined IP_SOF_BROADCAST_RECV || defined __DOXYGEN__ -#define IP_SOF_BROADCAST_RECV 0 -#endif - -/** - * IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back - * out on the netif where it was received. This should only be used for - * wireless networks. - * ATTENTION: When this is 1, make sure your netif driver correctly marks incoming - * link-layer-broadcast/multicast packets as such using the corresponding pbuf flags! - */ -#if !defined IP_FORWARD_ALLOW_TX_ON_RX_NETIF || defined __DOXYGEN__ -#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 -#endif -/** - * @} - */ - -/* - ---------------------------------- - ---------- ICMP options ---------- - ---------------------------------- -*/ -/** - * @defgroup lwip_opts_icmp ICMP - * @ingroup lwip_opts_ipv4 - * @{ - */ -/** - * LWIP_ICMP==1: Enable ICMP module inside the IP stack. - * Be careful, disable that make your product non-compliant to RFC1122 - */ -#if !defined LWIP_ICMP || defined __DOXYGEN__ -#define LWIP_ICMP 1 -#endif - -/** - * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. - */ -#if !defined ICMP_TTL || defined __DOXYGEN__ -#define ICMP_TTL IP_DEFAULT_TTL -#endif - -/** - * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) - */ -#if !defined LWIP_BROADCAST_PING || defined __DOXYGEN__ -#define LWIP_BROADCAST_PING 0 -#endif - -/** - * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) - */ -#if !defined LWIP_MULTICAST_PING || defined __DOXYGEN__ -#define LWIP_MULTICAST_PING 0 -#endif -/** - * @} - */ - -/* - --------------------------------- - ---------- RAW options ---------- - --------------------------------- -*/ -/** - * @defgroup lwip_opts_raw RAW - * @ingroup lwip_opts_callback - * @{ - */ -/** - * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. - */ -#if !defined LWIP_RAW || defined __DOXYGEN__ -#define LWIP_RAW 0 -#endif - -/** - * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. - */ -#if !defined RAW_TTL || defined __DOXYGEN__ -#define RAW_TTL IP_DEFAULT_TTL -#endif -/** - * @} - */ - -/* - ---------------------------------- - ---------- DHCP options ---------- - ---------------------------------- -*/ -/** - * @defgroup lwip_opts_dhcp DHCP - * @ingroup lwip_opts_ipv4 - * @{ - */ -/** - * LWIP_DHCP==1: Enable DHCP module. - */ -#if !defined LWIP_DHCP || defined __DOXYGEN__ -#define LWIP_DHCP 0 -#endif -#if !LWIP_IPV4 -/* disable DHCP when IPv4 is disabled */ -#undef LWIP_DHCP -#define LWIP_DHCP 0 -#endif /* !LWIP_IPV4 */ - -/** - * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. - */ -#if !defined DHCP_DOES_ARP_CHECK || defined __DOXYGEN__ -#define DHCP_DOES_ARP_CHECK (LWIP_DHCP && LWIP_ARP) -#endif - -/** - * LWIP_DHCP_BOOTP_FILE==1: Store offered_si_addr and boot_file_name. - */ -#if !defined LWIP_DHCP_BOOTP_FILE || defined __DOXYGEN__ -#define LWIP_DHCP_BOOTP_FILE 0 -#endif - -/** - * LWIP_DHCP_GETS_NTP==1: Request NTP servers with discover/select. For each - * response packet, an callback is called, which has to be provided by the port: - * void dhcp_set_ntp_servers(u8_t num_ntp_servers, ip_addr_t* ntp_server_addrs); -*/ -#if !defined LWIP_DHCP_GET_NTP_SRV || defined __DOXYGEN__ -#define LWIP_DHCP_GET_NTP_SRV 0 -#endif - -/** - * The maximum of NTP servers requested - */ -#if !defined LWIP_DHCP_MAX_NTP_SERVERS || defined __DOXYGEN__ -#define LWIP_DHCP_MAX_NTP_SERVERS 1 -#endif - -/** - * LWIP_DHCP_MAX_DNS_SERVERS > 0: Request DNS servers with discover/select. - * DNS servers received in the response are passed to DNS via @ref dns_setserver() - * (up to the maximum limit defined here). - */ -#if !defined LWIP_DHCP_MAX_DNS_SERVERS || defined __DOXYGEN__ -#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS -#endif -/** - * @} - */ - -/* - ------------------------------------ - ---------- AUTOIP options ---------- - ------------------------------------ -*/ -/** - * @defgroup lwip_opts_autoip AUTOIP - * @ingroup lwip_opts_ipv4 - * @{ - */ -/** - * LWIP_AUTOIP==1: Enable AUTOIP module. - */ -#if !defined LWIP_AUTOIP || defined __DOXYGEN__ -#define LWIP_AUTOIP 0 -#endif -#if !LWIP_IPV4 -/* disable AUTOIP when IPv4 is disabled */ -#undef LWIP_AUTOIP -#define LWIP_AUTOIP 0 -#endif /* !LWIP_IPV4 */ - -/** - * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on - * the same interface at the same time. - */ -#if !defined LWIP_DHCP_AUTOIP_COOP || defined __DOXYGEN__ -#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 (the DHCP client keeps - * running in this case). 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. - */ -#if !defined LWIP_DHCP_AUTOIP_COOP_TRIES || defined __DOXYGEN__ -#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 -#endif -/** - * @} - */ - -/* - ---------------------------------- - ----- SNMP MIB2 support ----- - ---------------------------------- -*/ -/** - * @defgroup lwip_opts_mib2 SNMP MIB2 callbacks - * @ingroup lwip_opts_infrastructure - * @{ - */ -/** - * LWIP_MIB2_CALLBACKS==1: Turn on SNMP MIB2 callbacks. - * Turn this on to get callbacks needed to implement MIB2. - * Usually MIB2_STATS should be enabled, too. - */ -#if !defined LWIP_MIB2_CALLBACKS || defined __DOXYGEN__ -#define LWIP_MIB2_CALLBACKS 0 -#endif -/** - * @} - */ - -/* - ---------------------------------- - -------- Multicast options ------- - ---------------------------------- -*/ -/** - * @defgroup lwip_opts_multicast Multicast - * @ingroup lwip_opts_infrastructure - * @{ - */ -/** - * LWIP_MULTICAST_TX_OPTIONS==1: Enable multicast TX support like the socket options - * IP_MULTICAST_TTL/IP_MULTICAST_IF/IP_MULTICAST_LOOP, as well as (currently only) - * core support for the corresponding IPv6 options. - */ -#if !defined LWIP_MULTICAST_TX_OPTIONS || defined __DOXYGEN__ -#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && (LWIP_UDP || LWIP_RAW)) -#endif -/** - * @} - */ - -/* - ---------------------------------- - ---------- IGMP options ---------- - ---------------------------------- -*/ -/** - * @defgroup lwip_opts_igmp IGMP - * @ingroup lwip_opts_ipv4 - * @{ - */ -/** - * LWIP_IGMP==1: Turn on IGMP module. - */ -#if !defined LWIP_IGMP || defined __DOXYGEN__ -#define LWIP_IGMP 0 -#endif -#if !LWIP_IPV4 -#undef LWIP_IGMP -#define LWIP_IGMP 0 -#endif -/** - * @} - */ - -/* - ---------------------------------- - ---------- DNS options ----------- - ---------------------------------- -*/ -/** - * @defgroup lwip_opts_dns DNS - * @ingroup lwip_opts_callback - * @{ - */ -/** - * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS - * transport. - */ -#if !defined LWIP_DNS || defined __DOXYGEN__ -#define LWIP_DNS 0 -#endif - -/** DNS maximum number of entries to maintain locally. */ -#if !defined DNS_TABLE_SIZE || defined __DOXYGEN__ -#define DNS_TABLE_SIZE 4 -#endif - -/** DNS maximum host name length supported in the name table. */ -#if !defined DNS_MAX_NAME_LENGTH || defined __DOXYGEN__ -#define DNS_MAX_NAME_LENGTH 256 -#endif - -/** The maximum of DNS servers - * The first server can be initialized automatically by defining - * DNS_SERVER_ADDRESS(ipaddr), where 'ipaddr' is an 'ip_addr_t*' - */ -#if !defined DNS_MAX_SERVERS || defined __DOXYGEN__ -#define DNS_MAX_SERVERS 2 -#endif - -/** DNS maximum number of retries when asking for a name, before "timeout". */ -#if !defined DNS_MAX_RETRIES || defined __DOXYGEN__ -#define DNS_MAX_RETRIES 4 -#endif - -/** DNS do a name checking between the query and the response. */ -#if !defined DNS_DOES_NAME_CHECK || defined __DOXYGEN__ -#define DNS_DOES_NAME_CHECK 1 -#endif - -/** LWIP_DNS_SECURE: controls the security level of the DNS implementation - * Use all DNS security features by default. - * This is overridable but should only be needed by very small targets - * or when using against non standard DNS servers. */ -#if !defined LWIP_DNS_SECURE || defined __DOXYGEN__ -#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) -#endif - -/* A list of DNS security features follows */ -#define LWIP_DNS_SECURE_RAND_XID 1 -#define LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING 2 -#define LWIP_DNS_SECURE_RAND_SRC_PORT 4 - -/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, you have to define an initializer: - * \#define DNS_LOCAL_HOSTLIST_INIT {DNS_LOCAL_HOSTLIST_ELEM("host_ip4", IPADDR4_INIT_BYTES(1,2,3,4)), \ - * DNS_LOCAL_HOSTLIST_ELEM("host_ip6", IPADDR6_INIT_HOST(123, 234, 345, 456)} - * - * Instead, you can also use an external function: - * \#define DNS_LOOKUP_LOCAL_EXTERN(x) extern err_t my_lookup_function(const char *name, ip_addr_t *addr, u8_t dns_addrtype) - * that looks up the IP address and returns ERR_OK if found (LWIP_DNS_ADDRTYPE_xxx is passed in dns_addrtype). - */ -#if !defined DNS_LOCAL_HOSTLIST || defined __DOXYGEN__ -#define DNS_LOCAL_HOSTLIST 0 -#endif /* DNS_LOCAL_HOSTLIST */ - -/** If this is turned on, the local host-list can be dynamically changed - * at runtime. */ -#if !defined DNS_LOCAL_HOSTLIST_IS_DYNAMIC || defined __DOXYGEN__ -#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - -/** Set this to 1 to enable querying ".local" names via mDNS - * using a One-Shot Multicast DNS Query */ -#if !defined LWIP_DNS_SUPPORT_MDNS_QUERIES || defined __DOXYGEN__ -#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 -#endif -/** - * @} - */ - -/* - --------------------------------- - ---------- UDP options ---------- - --------------------------------- -*/ -/** - * @defgroup lwip_opts_udp UDP - * @ingroup lwip_opts_callback - * @{ - */ -/** - * LWIP_UDP==1: Turn on UDP. - */ -#if !defined LWIP_UDP || defined __DOXYGEN__ -#define LWIP_UDP 1 -#endif - -/** - * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) - */ -#if !defined LWIP_UDPLITE || defined __DOXYGEN__ -#define LWIP_UDPLITE 0 -#endif - -/** - * UDP_TTL: Default Time-To-Live value. - */ -#if !defined UDP_TTL || defined __DOXYGEN__ -#define UDP_TTL IP_DEFAULT_TTL -#endif - -/** - * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. - */ -#if !defined LWIP_NETBUF_RECVINFO || defined __DOXYGEN__ -#define LWIP_NETBUF_RECVINFO 0 -#endif -/** - * @} - */ - -/* - --------------------------------- - ---------- TCP options ---------- - --------------------------------- -*/ -/** - * @defgroup lwip_opts_tcp TCP - * @ingroup lwip_opts_callback - * @{ - */ -/** - * LWIP_TCP==1: Turn on TCP. - */ -#if !defined LWIP_TCP || defined __DOXYGEN__ -#define LWIP_TCP 1 -#endif - -/** - * TCP_TTL: Default Time-To-Live value. - */ -#if !defined TCP_TTL || defined __DOXYGEN__ -#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. - * ATTENTION: when using TCP_RCV_SCALE, TCP_WND is the total size - * with scaling applied. Maximum window value in the TCP header - * will be TCP_WND >> TCP_RCV_SCALE - */ -#if !defined TCP_WND || defined __DOXYGEN__ -#define TCP_WND (4 * TCP_MSS) -#endif - -/** - * TCP_MAXRTX: Maximum number of retransmissions of data segments. - */ -#if !defined TCP_MAXRTX || defined __DOXYGEN__ -#define TCP_MAXRTX 12 -#endif - -/** - * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. - */ -#if !defined TCP_SYNMAXRTX || defined __DOXYGEN__ -#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. - */ -#if !defined TCP_QUEUE_OOSEQ || defined __DOXYGEN__ -#define TCP_QUEUE_OOSEQ LWIP_TCP -#endif - -/** - * LWIP_TCP_SACK_OUT==1: TCP will support sending selective acknowledgements (SACKs). - */ -#if !defined LWIP_TCP_SACK_OUT || defined __DOXYGEN__ -#define LWIP_TCP_SACK_OUT 0 -#endif - -/** - * LWIP_TCP_MAX_SACK_NUM: The maximum number of SACK values to include in TCP segments. - * Must be at least 1, but is only used if LWIP_TCP_SACK_OUT is enabled. - * NOTE: Even though we never send more than 3 or 4 SACK ranges in a single segment - * (depending on other options), setting this option to values greater than 4 is not pointless. - * This is basically the max number of SACK ranges we want to keep track of. - * As new data is delivered, some of the SACK ranges may be removed or merged. - * In that case some of those older SACK ranges may be used again. - * The amount of memory used to store SACK ranges is LWIP_TCP_MAX_SACK_NUM * 8 bytes for each TCP PCB. - */ -#if !defined LWIP_TCP_MAX_SACK_NUM || defined __DOXYGEN__ -#define LWIP_TCP_MAX_SACK_NUM 4 -#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. - */ -#if !defined TCP_MSS || defined __DOXYGEN__ -#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. - */ -#if !defined TCP_CALCULATE_EFF_SEND_MSS || defined __DOXYGEN__ -#define TCP_CALCULATE_EFF_SEND_MSS 1 -#endif - - -/** - * TCP_SND_BUF: TCP sender buffer space (bytes). - * To achieve good performance, this should be at least 2 * TCP_MSS. - */ -#if !defined TCP_SND_BUF || defined __DOXYGEN__ -#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. - */ -#if !defined TCP_SND_QUEUELEN || defined __DOXYGEN__ -#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). - */ -#if !defined TCP_SNDLOWAT || defined __DOXYGEN__ -#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) -#endif - -/** - * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be less - * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below - * this number, select returns writable (combined with TCP_SNDLOWAT). - */ -#if !defined TCP_SNDQUEUELOWAT || defined __DOXYGEN__ -#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) -#endif - -/** - * TCP_OOSEQ_MAX_BYTES: The default maximum number of bytes queued on ooseq per - * pcb if TCP_OOSEQ_BYTES_LIMIT is not defined. Default is 0 (no limit). - * Only valid for TCP_QUEUE_OOSEQ==1. - */ -#if !defined TCP_OOSEQ_MAX_BYTES || defined __DOXYGEN__ -#define TCP_OOSEQ_MAX_BYTES 0 -#endif - -/** - * TCP_OOSEQ_BYTES_LIMIT(pcb): Return the maximum number of bytes to be queued - * on ooseq per pcb, given the pcb. Only valid for TCP_QUEUE_OOSEQ==1 && - * TCP_OOSEQ_MAX_BYTES==1. - * Use this to override TCP_OOSEQ_MAX_BYTES to a dynamic value per pcb. - */ -#if !defined TCP_OOSEQ_BYTES_LIMIT -#if TCP_OOSEQ_MAX_BYTES -#define TCP_OOSEQ_BYTES_LIMIT(pcb) TCP_OOSEQ_MAX_BYTES -#elif defined __DOXYGEN__ -#define TCP_OOSEQ_BYTES_LIMIT(pcb) -#endif -#endif - -/** - * TCP_OOSEQ_MAX_PBUFS: The default maximum number of pbufs queued on ooseq per - * pcb if TCP_OOSEQ_BYTES_LIMIT is not defined. Default is 0 (no limit). - * Only valid for TCP_QUEUE_OOSEQ==1. - */ -#if !defined TCP_OOSEQ_MAX_PBUFS || defined __DOXYGEN__ -#define TCP_OOSEQ_MAX_PBUFS 0 -#endif - -/** - * TCP_OOSEQ_PBUFS_LIMIT(pcb): Return the maximum number of pbufs to be queued - * on ooseq per pcb, given the pcb. Only valid for TCP_QUEUE_OOSEQ==1 && - * TCP_OOSEQ_MAX_PBUFS==1. - * Use this to override TCP_OOSEQ_MAX_PBUFS to a dynamic value per pcb. - */ -#if !defined TCP_OOSEQ_PBUFS_LIMIT -#if TCP_OOSEQ_MAX_PBUFS -#define TCP_OOSEQ_PBUFS_LIMIT(pcb) TCP_OOSEQ_MAX_PBUFS -#elif defined __DOXYGEN__ -#define TCP_OOSEQ_PBUFS_LIMIT(pcb) -#endif -#endif - -/** - * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. - */ -#if !defined TCP_LISTEN_BACKLOG || defined __DOXYGEN__ -#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). - */ -#if !defined TCP_DEFAULT_LISTEN_BACKLOG || defined __DOXYGEN__ -#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. - */ -#if !defined TCP_OVERSIZE || defined __DOXYGEN__ -#define TCP_OVERSIZE TCP_MSS -#endif - -/** - * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. - * The timestamp option is currently only used to help remote hosts, it is not - * really used locally. Therefore, it is only enabled when a TS option is - * received in the initial SYN packet from a remote host. - */ -#if !defined LWIP_TCP_TIMESTAMPS || defined __DOXYGEN__ -#define LWIP_TCP_TIMESTAMPS 0 -#endif - -/** - * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an - * explicit window update - */ -#if !defined TCP_WND_UPDATE_THRESHOLD || defined __DOXYGEN__ -#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 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. This is the default. - */ -#if !defined(LWIP_EVENT_API) && !defined(LWIP_CALLBACK_API) || defined __DOXYGEN__ -#define LWIP_EVENT_API 0 -#define LWIP_CALLBACK_API 1 -#else -#ifndef LWIP_EVENT_API -#define LWIP_EVENT_API 0 -#endif -#ifndef LWIP_CALLBACK_API -#define LWIP_CALLBACK_API 0 -#endif -#endif - -/** - * LWIP_WND_SCALE and TCP_RCV_SCALE: - * Set LWIP_WND_SCALE to 1 to enable window scaling. - * Set TCP_RCV_SCALE to the desired scaling factor (shift count in the - * range of [0..14]). - * When LWIP_WND_SCALE is enabled but TCP_RCV_SCALE is 0, we can use a large - * send window while having a small receive window only. - */ -#if !defined LWIP_WND_SCALE || defined __DOXYGEN__ -#define LWIP_WND_SCALE 0 -#define TCP_RCV_SCALE 0 -#endif - -/** - * LWIP_TCP_PCB_NUM_EXT_ARGS: - * When this is > 0, every tcp pcb (including listen pcb) includes a number of - * additional argument entries in an array (see tcp_ext_arg_alloc_id) - */ -#if !defined LWIP_TCP_PCB_NUM_EXT_ARGS || defined __DOXYGEN__ -#define LWIP_TCP_PCB_NUM_EXT_ARGS 0 -#endif - -/** LWIP_ALTCP==1: enable the altcp API. - * altcp is an abstraction layer that prevents applications linking against the - * tcp.h functions but provides the same functionality. It is used to e.g. add - * SSL/TLS or proxy-connect support to an application written for the tcp callback - * API without that application knowing the protocol details. - * - * With LWIP_ALTCP==0, applications written against the altcp API can still be - * compiled but are directly linked against the tcp.h callback API and then - * cannot use layered protocols. - * - * See @ref altcp_api - */ -#if !defined LWIP_ALTCP || defined __DOXYGEN__ -#define LWIP_ALTCP 0 -#endif - -/** LWIP_ALTCP_TLS==1: enable TLS support for altcp API. - * This needs a port of the functions in altcp_tls.h to a TLS library. - * A port to ARM mbedtls is provided with lwIP, see apps/altcp_tls/ directory - * and LWIP_ALTCP_TLS_MBEDTLS option. - */ -#if !defined LWIP_ALTCP_TLS || defined __DOXYGEN__ -#define LWIP_ALTCP_TLS 0 -#endif - -/** - * @} - */ - -/* - ---------------------------------- - ---------- Pbuf options ---------- - ---------------------------------- -*/ -/** - * @defgroup lwip_opts_pbuf PBUF - * @ingroup lwip_opts - * @{ - */ -/** - * 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. - */ -#if !defined PBUF_LINK_HLEN || defined __DOXYGEN__ -#if defined LWIP_HOOK_VLAN_SET && !defined __DOXYGEN__ -#define PBUF_LINK_HLEN (18 + ETH_PAD_SIZE) -#else /* LWIP_HOOK_VLAN_SET */ -#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) -#endif /* LWIP_HOOK_VLAN_SET */ -#endif - -/** - * PBUF_LINK_ENCAPSULATION_HLEN: the number of bytes that should be allocated - * for an additional encapsulation header before ethernet headers (e.g. 802.11) - */ -#if !defined PBUF_LINK_ENCAPSULATION_HLEN || defined __DOXYGEN__ -#define PBUF_LINK_ENCAPSULATION_HLEN 0 -#endif - -/** - * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is - * designed to accommodate single full size TCP frame in one pbuf, including - * TCP_MSS, IP header, and link header. - */ -#if !defined PBUF_POOL_BUFSIZE || defined __DOXYGEN__ -#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) -#endif - -/** - * LWIP_PBUF_REF_T: Refcount type in pbuf. - * Default width of u8_t can be increased if 255 refs are not enough for you. - */ -#if !defined LWIP_PBUF_REF_T || defined __DOXYGEN__ -#define LWIP_PBUF_REF_T u8_t -#endif -/** - * @} - */ - -/* - ------------------------------------------------ - ---------- Network Interfaces options ---------- - ------------------------------------------------ -*/ -/** - * @defgroup lwip_opts_netif NETIF - * @ingroup lwip_opts - * @{ - */ -/** - * LWIP_SINGLE_NETIF==1: use a single netif only. This is the common case for - * small real-life targets. Some code like routing etc. can be left out. - */ -#if !defined LWIP_SINGLE_NETIF || defined __DOXYGEN__ -#define LWIP_SINGLE_NETIF 0 -#endif - -/** - * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname - * field. - */ -#if !defined LWIP_NETIF_HOSTNAME || defined __DOXYGEN__ -#define LWIP_NETIF_HOSTNAME 0 -#endif - -/** - * LWIP_NETIF_API==1: Support netif api (in netifapi.c) - */ -#if !defined LWIP_NETIF_API || defined __DOXYGEN__ -#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 acquisition) - */ -#if !defined LWIP_NETIF_STATUS_CALLBACK || defined __DOXYGEN__ -#define LWIP_NETIF_STATUS_CALLBACK 0 -#endif - -/** - * LWIP_NETIF_EXT_STATUS_CALLBACK==1: Support an extended callback function - * for several netif related event that supports multiple subscribers. - * @see netif_ext_status_callback - */ -#if !defined LWIP_NETIF_EXT_STATUS_CALLBACK || defined __DOXYGEN__ -#define LWIP_NETIF_EXT_STATUS_CALLBACK 0 -#endif - -/** - * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface - * whenever the link changes (i.e., link down) - */ -#if !defined LWIP_NETIF_LINK_CALLBACK || defined __DOXYGEN__ -#define LWIP_NETIF_LINK_CALLBACK 0 -#endif - -/** - * LWIP_NETIF_REMOVE_CALLBACK==1: Support a callback function that is called - * when a netif has been removed - */ -#if !defined LWIP_NETIF_REMOVE_CALLBACK || defined __DOXYGEN__ -#define LWIP_NETIF_REMOVE_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. - */ -#if !defined LWIP_NETIF_HWADDRHINT || defined __DOXYGEN__ -#define LWIP_NETIF_HWADDRHINT 0 -#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! - * - * ATTENTION: a driver should *NOT* rely on getting single pbufs but check TX - * pbufs for being in one piece. If not, @ref pbuf_clone can be used to get - * a single pbuf: - * if (p->next != NULL) { - * struct pbuf *q = pbuf_clone(PBUF_RAW, PBUF_RAM, p); - * if (q == NULL) { - * return ERR_MEM; - * } - * p = q; ATTENTION: do NOT free the old 'p' as the ref belongs to the caller! - * } - */ -#if !defined LWIP_NETIF_TX_SINGLE_PBUF || defined __DOXYGEN__ -#define LWIP_NETIF_TX_SINGLE_PBUF 0 -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - -/** - * LWIP_NUM_NETIF_CLIENT_DATA: Number of clients that may store - * data in client_data member array of struct netif (max. 256). - */ -#if !defined LWIP_NUM_NETIF_CLIENT_DATA || defined __DOXYGEN__ -#define LWIP_NUM_NETIF_CLIENT_DATA 0 -#endif -/** - * @} - */ - -/* - ------------------------------------ - ---------- LOOPIF options ---------- - ------------------------------------ -*/ -/** - * @defgroup lwip_opts_loop Loopback interface - * @ingroup lwip_opts_netif - * @{ - */ -/** - * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1). - * This is only needed when no real netifs are available. If at least one other - * netif is available, loopback traffic uses this netif. - */ -#if !defined LWIP_HAVE_LOOPIF || defined __DOXYGEN__ -#define LWIP_HAVE_LOOPIF (LWIP_NETIF_LOOPBACK && !LWIP_SINGLE_NETIF) -#endif - -/** - * LWIP_LOOPIF_MULTICAST==1: Support multicast/IGMP on loop interface (127.0.0.1). - */ -#if !defined LWIP_LOOPIF_MULTICAST || defined __DOXYGEN__ -#define LWIP_LOOPIF_MULTICAST 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. - */ -#if !defined LWIP_NETIF_LOOPBACK || defined __DOXYGEN__ -#define LWIP_NETIF_LOOPBACK 0 -#endif - -/** - * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback - * sending for each netif (0 = disabled) - */ -#if !defined LWIP_LOOPBACK_MAX_PBUFS || defined __DOXYGEN__ -#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. - */ -#if !defined LWIP_NETIF_LOOPBACK_MULTITHREADING || defined __DOXYGEN__ -#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) -#endif -/** - * @} - */ - -/* - ------------------------------------ - ---------- Thread options ---------- - ------------------------------------ -*/ -/** - * @defgroup lwip_opts_thread Threading - * @ingroup lwip_opts_infrastructure - * @{ - */ -/** - * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. - */ -#if !defined TCPIP_THREAD_NAME || defined __DOXYGEN__ -#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. - */ -#if !defined TCPIP_THREAD_STACKSIZE || defined __DOXYGEN__ -#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. - */ -#if !defined TCPIP_THREAD_PRIO || defined __DOXYGEN__ -#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. - */ -#if !defined TCPIP_MBOX_SIZE || defined __DOXYGEN__ -#define TCPIP_MBOX_SIZE 0 -#endif - -/** - * Define this to something that triggers a watchdog. This is called from - * tcpip_thread after processing a message. - */ -#if !defined LWIP_TCPIP_THREAD_ALIVE || defined __DOXYGEN__ -#define LWIP_TCPIP_THREAD_ALIVE() -#endif - -/** - * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. - */ -#if !defined SLIPIF_THREAD_NAME || defined __DOXYGEN__ -#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. - */ -#if !defined SLIPIF_THREAD_STACKSIZE || defined __DOXYGEN__ -#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. - */ -#if !defined SLIPIF_THREAD_PRIO || defined __DOXYGEN__ -#define SLIPIF_THREAD_PRIO 1 -#endif - -/** - * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. - */ -#if !defined DEFAULT_THREAD_NAME || defined __DOXYGEN__ -#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. - */ -#if !defined DEFAULT_THREAD_STACKSIZE || defined __DOXYGEN__ -#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. - */ -#if !defined DEFAULT_THREAD_PRIO || defined __DOXYGEN__ -#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. - */ -#if !defined DEFAULT_RAW_RECVMBOX_SIZE || defined __DOXYGEN__ -#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. - */ -#if !defined DEFAULT_UDP_RECVMBOX_SIZE || defined __DOXYGEN__ -#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. - */ -#if !defined DEFAULT_TCP_RECVMBOX_SIZE || defined __DOXYGEN__ -#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. - */ -#if !defined DEFAULT_ACCEPTMBOX_SIZE || defined __DOXYGEN__ -#define DEFAULT_ACCEPTMBOX_SIZE 0 -#endif -/** - * @} - */ - -/* - ---------------------------------------------- - ---------- Sequential layer options ---------- - ---------------------------------------------- -*/ -/** - * @defgroup lwip_opts_netconn Netconn - * @ingroup lwip_opts_threadsafe_apis - * @{ - */ -/** - * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) - */ -#if !defined LWIP_NETCONN || defined __DOXYGEN__ -#define LWIP_NETCONN 1 -#endif - -/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout to create - * timers running in tcpip_thread from another thread. - */ -#if !defined LWIP_TCPIP_TIMEOUT || defined __DOXYGEN__ -#define LWIP_TCPIP_TIMEOUT 0 -#endif - -/** LWIP_NETCONN_SEM_PER_THREAD==1: Use one (thread-local) semaphore per - * thread calling socket/netconn functions instead of allocating one - * semaphore per netconn (and per select etc.) - * ATTENTION: a thread-local semaphore for API calls is needed: - * - LWIP_NETCONN_THREAD_SEM_GET() returning a sys_sem_t* - * - LWIP_NETCONN_THREAD_SEM_ALLOC() creating the semaphore - * - LWIP_NETCONN_THREAD_SEM_FREE() freeing the semaphore - * The latter 2 can be invoked up by calling netconn_thread_init()/netconn_thread_cleanup(). - * Ports may call these for threads created with sys_thread_new(). - */ -#if !defined LWIP_NETCONN_SEM_PER_THREAD || defined __DOXYGEN__ -#define LWIP_NETCONN_SEM_PER_THREAD 0 -#endif - -/** LWIP_NETCONN_FULLDUPLEX==1: Enable code that allows reading from one thread, - * writing from a 2nd thread and closing from a 3rd thread at the same time. - * ATTENTION: This is currently really alpha! Some requirements: - * - LWIP_NETCONN_SEM_PER_THREAD==1 is required to use one socket/netconn from - * multiple threads at once - * - sys_mbox_free() has to unblock receive tasks waiting on recvmbox/acceptmbox - * and prevent a task pending on this during/after deletion - */ -#if !defined LWIP_NETCONN_FULLDUPLEX || defined __DOXYGEN__ -#define LWIP_NETCONN_FULLDUPLEX 0 -#endif -/** - * @} - */ - -/* - ------------------------------------ - ---------- Socket options ---------- - ------------------------------------ -*/ -/** - * @defgroup lwip_opts_socket Sockets - * @ingroup lwip_opts_threadsafe_apis - * @{ - */ -/** - * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) - */ -#if !defined LWIP_SOCKET || defined __DOXYGEN__ -#define LWIP_SOCKET 1 -#endif - -/** - * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names through defines. - * LWIP_COMPAT_SOCKETS==2: Same as ==1 but correctly named functions are created. - * While this helps code completion, it might conflict with existing libraries. - * (only used if you use sockets.c) - */ -#if !defined LWIP_COMPAT_SOCKETS || defined __DOXYGEN__ -#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) - */ -#if !defined LWIP_POSIX_SOCKETS_IO_NAMES || defined __DOXYGEN__ -#define LWIP_POSIX_SOCKETS_IO_NAMES 1 -#endif - -/** - * LWIP_SOCKET_OFFSET==n: Increases the file descriptor number created by LwIP with n. - * This can be useful when there are multiple APIs which create file descriptors. - * When they all start with a different offset and you won't make them overlap you can - * re implement read/write/close/ioctl/fnctl to send the requested action to the right - * library (sharing select will need more work though). - */ -#if !defined LWIP_SOCKET_OFFSET || defined __DOXYGEN__ -#define LWIP_SOCKET_OFFSET 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) - */ -#if !defined LWIP_TCP_KEEPALIVE || defined __DOXYGEN__ -#define LWIP_TCP_KEEPALIVE 0 -#endif - -/** - * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and - * SO_SNDTIMEO processing. - */ -#if !defined LWIP_SO_SNDTIMEO || defined __DOXYGEN__ -#define LWIP_SO_SNDTIMEO 0 -#endif - -/** - * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and - * SO_RCVTIMEO processing. - */ -#if !defined LWIP_SO_RCVTIMEO || defined __DOXYGEN__ -#define LWIP_SO_RCVTIMEO 0 -#endif - -/** - * LWIP_SO_SNDRCVTIMEO_NONSTANDARD==1: SO_RCVTIMEO/SO_SNDTIMEO take an int - * (milliseconds, much like winsock does) instead of a struct timeval (default). - */ -#if !defined LWIP_SO_SNDRCVTIMEO_NONSTANDARD || defined __DOXYGEN__ -#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 -#endif - -/** - * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. - */ -#if !defined LWIP_SO_RCVBUF || defined __DOXYGEN__ -#define LWIP_SO_RCVBUF 0 -#endif - -/** - * LWIP_SO_LINGER==1: Enable SO_LINGER processing. - */ -#if !defined LWIP_SO_LINGER || defined __DOXYGEN__ -#define LWIP_SO_LINGER 0 -#endif - -/** - * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. - */ -#if !defined RECV_BUFSIZE_DEFAULT || defined __DOXYGEN__ -#define RECV_BUFSIZE_DEFAULT INT_MAX -#endif - -/** - * By default, TCP socket/netconn close waits 20 seconds max to send the FIN - */ -#if !defined LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT || defined __DOXYGEN__ -#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 -#endif - -/** - * SO_REUSE==1: Enable SO_REUSEADDR option. - */ -#if !defined SO_REUSE || defined __DOXYGEN__ -#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! - */ -#if !defined SO_REUSE_RXTOALL || defined __DOXYGEN__ -#define SO_REUSE_RXTOALL 0 -#endif - -/** - * LWIP_FIONREAD_LINUXMODE==0 (default): ioctl/FIONREAD returns the amount of - * pending data in the network buffer. This is the way windows does it. It's - * the default for lwIP since it is smaller. - * LWIP_FIONREAD_LINUXMODE==1: ioctl/FIONREAD returns the size of the next - * pending datagram in bytes. This is the way linux does it. This code is only - * here for compatibility. - */ -#if !defined LWIP_FIONREAD_LINUXMODE || defined __DOXYGEN__ -#define LWIP_FIONREAD_LINUXMODE 0 -#endif - -/** - * LWIP_SOCKET_SELECT==1 (default): enable select() for sockets (uses a netconn - * callback to keep track of events). - * This saves RAM (counters per socket) and code (netconn event callback), which - * should improve performance a bit). - */ -#if !defined LWIP_SOCKET_SELECT || defined __DOXYGEN__ -#define LWIP_SOCKET_SELECT 1 -#endif - -/** - * LWIP_SOCKET_POLL==1 (default): enable poll() for sockets (including - * struct pollfd, nfds_t, and constants) - */ -#if !defined LWIP_SOCKET_POLL || defined __DOXYGEN__ -#define LWIP_SOCKET_POLL 1 -#endif -/** - * @} - */ - -/* - ---------------------------------------- - ---------- Statistics options ---------- - ---------------------------------------- -*/ -/** - * @defgroup lwip_opts_stats Statistics - * @ingroup lwip_opts_debug - * @{ - */ -/** - * LWIP_STATS==1: Enable statistics collection in lwip_stats. - */ -#if !defined LWIP_STATS || defined __DOXYGEN__ -#define LWIP_STATS 1 -#endif - -#if LWIP_STATS - -/** - * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. - */ -#if !defined LWIP_STATS_DISPLAY || defined __DOXYGEN__ -#define LWIP_STATS_DISPLAY 0 -#endif - -/** - * LINK_STATS==1: Enable link stats. - */ -#if !defined LINK_STATS || defined __DOXYGEN__ -#define LINK_STATS 1 -#endif - -/** - * ETHARP_STATS==1: Enable etharp stats. - */ -#if !defined ETHARP_STATS || defined __DOXYGEN__ -#define ETHARP_STATS (LWIP_ARP) -#endif - -/** - * IP_STATS==1: Enable IP stats. - */ -#if !defined IP_STATS || defined __DOXYGEN__ -#define IP_STATS 1 -#endif - -/** - * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is - * on if using either frag or reass. - */ -#if !defined IPFRAG_STATS || defined __DOXYGEN__ -#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) -#endif - -/** - * ICMP_STATS==1: Enable ICMP stats. - */ -#if !defined ICMP_STATS || defined __DOXYGEN__ -#define ICMP_STATS 1 -#endif - -/** - * IGMP_STATS==1: Enable IGMP stats. - */ -#if !defined IGMP_STATS || defined __DOXYGEN__ -#define IGMP_STATS (LWIP_IGMP) -#endif - -/** - * UDP_STATS==1: Enable UDP stats. Default is on if - * UDP enabled, otherwise off. - */ -#if !defined UDP_STATS || defined __DOXYGEN__ -#define UDP_STATS (LWIP_UDP) -#endif - -/** - * TCP_STATS==1: Enable TCP stats. Default is on if TCP - * enabled, otherwise off. - */ -#if !defined TCP_STATS || defined __DOXYGEN__ -#define TCP_STATS (LWIP_TCP) -#endif - -/** - * MEM_STATS==1: Enable mem.c stats. - */ -#if !defined MEM_STATS || defined __DOXYGEN__ -#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) -#endif - -/** - * MEMP_STATS==1: Enable memp.c pool stats. - */ -#if !defined MEMP_STATS || defined __DOXYGEN__ -#define MEMP_STATS (MEMP_MEM_MALLOC == 0) -#endif - -/** - * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). - */ -#if !defined SYS_STATS || defined __DOXYGEN__ -#define SYS_STATS (NO_SYS == 0) -#endif - -/** - * IP6_STATS==1: Enable IPv6 stats. - */ -#if !defined IP6_STATS || defined __DOXYGEN__ -#define IP6_STATS (LWIP_IPV6) -#endif - -/** - * ICMP6_STATS==1: Enable ICMP for IPv6 stats. - */ -#if !defined ICMP6_STATS || defined __DOXYGEN__ -#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) -#endif - -/** - * IP6_FRAG_STATS==1: Enable IPv6 fragmentation stats. - */ -#if !defined IP6_FRAG_STATS || defined __DOXYGEN__ -#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) -#endif - -/** - * MLD6_STATS==1: Enable MLD for IPv6 stats. - */ -#if !defined MLD6_STATS || defined __DOXYGEN__ -#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) -#endif - -/** - * ND6_STATS==1: Enable Neighbor discovery for IPv6 stats. - */ -#if !defined ND6_STATS || defined __DOXYGEN__ -#define ND6_STATS (LWIP_IPV6) -#endif - -/** - * MIB2_STATS==1: Stats for SNMP MIB2. - */ -#if !defined MIB2_STATS || defined __DOXYGEN__ -#define MIB2_STATS 0 -#endif - -#else - -#define LINK_STATS 0 -#define ETHARP_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 -#define IP6_STATS 0 -#define ICMP6_STATS 0 -#define IP6_FRAG_STATS 0 -#define MLD6_STATS 0 -#define ND6_STATS 0 -#define MIB2_STATS 0 - -#endif /* LWIP_STATS */ -/** - * @} - */ - -/* - -------------------------------------- - ---------- Checksum options ---------- - -------------------------------------- -*/ -/** - * @defgroup lwip_opts_checksum Checksum - * @ingroup lwip_opts_infrastructure - * @{ - */ -/** - * LWIP_CHECKSUM_CTRL_PER_NETIF==1: Checksum generation/check can be enabled/disabled - * per netif. - * ATTENTION: if enabled, the CHECKSUM_GEN_* and CHECKSUM_CHECK_* defines must be enabled! - */ -#if !defined LWIP_CHECKSUM_CTRL_PER_NETIF || defined __DOXYGEN__ -#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 -#endif - -/** - * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. - */ -#if !defined CHECKSUM_GEN_IP || defined __DOXYGEN__ -#define CHECKSUM_GEN_IP 1 -#endif - -/** - * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. - */ -#if !defined CHECKSUM_GEN_UDP || defined __DOXYGEN__ -#define CHECKSUM_GEN_UDP 1 -#endif - -/** - * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. - */ -#if !defined CHECKSUM_GEN_TCP || defined __DOXYGEN__ -#define CHECKSUM_GEN_TCP 1 -#endif - -/** - * CHECKSUM_GEN_ICMP==1: Generate checksums in software for outgoing ICMP packets. - */ -#if !defined CHECKSUM_GEN_ICMP || defined __DOXYGEN__ -#define CHECKSUM_GEN_ICMP 1 -#endif - -/** - * CHECKSUM_GEN_ICMP6==1: Generate checksums in software for outgoing ICMP6 packets. - */ -#if !defined CHECKSUM_GEN_ICMP6 || defined __DOXYGEN__ -#define CHECKSUM_GEN_ICMP6 1 -#endif - -/** - * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. - */ -#if !defined CHECKSUM_CHECK_IP || defined __DOXYGEN__ -#define CHECKSUM_CHECK_IP 1 -#endif - -/** - * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. - */ -#if !defined CHECKSUM_CHECK_UDP || defined __DOXYGEN__ -#define CHECKSUM_CHECK_UDP 1 -#endif - -/** - * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. - */ -#if !defined CHECKSUM_CHECK_TCP || defined __DOXYGEN__ -#define CHECKSUM_CHECK_TCP 1 -#endif - -/** - * CHECKSUM_CHECK_ICMP==1: Check checksums in software for incoming ICMP packets. - */ -#if !defined CHECKSUM_CHECK_ICMP || defined __DOXYGEN__ -#define CHECKSUM_CHECK_ICMP 1 -#endif - -/** - * CHECKSUM_CHECK_ICMP6==1: Check checksums in software for incoming ICMPv6 packets - */ -#if !defined CHECKSUM_CHECK_ICMP6 || defined __DOXYGEN__ -#define CHECKSUM_CHECK_ICMP6 1 -#endif - -/** - * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from - * application buffers to pbufs. - */ -#if !defined LWIP_CHECKSUM_ON_COPY || defined __DOXYGEN__ -#define LWIP_CHECKSUM_ON_COPY 0 -#endif -/** - * @} - */ - -/* - --------------------------------------- - ---------- IPv6 options --------------- - --------------------------------------- -*/ -/** - * @defgroup lwip_opts_ipv6 IPv6 - * @ingroup lwip_opts - * @{ - */ -/** - * LWIP_IPV6==1: Enable IPv6 - */ -#if !defined LWIP_IPV6 || defined __DOXYGEN__ -#define LWIP_IPV6 0 -#endif - -/** - * IPV6_REASS_MAXAGE: Maximum time (in multiples of IP6_REASS_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. - */ -#if !defined IPV6_REASS_MAXAGE || defined __DOXYGEN__ -#define IPV6_REASS_MAXAGE 60 -#endif - -/** - * LWIP_IPV6_SCOPES==1: Enable support for IPv6 address scopes, ensuring that - * e.g. link-local addresses are really treated as link-local. Disable this - * setting only for single-interface configurations. - * All addresses that have a scope according to the default policy (link-local - * unicast addresses, interface-local and link-local multicast addresses) should - * now have a zone set on them before being passed to the core API, although - * lwIP will currently attempt to select a zone on the caller's behalf when - * necessary. Applications that directly assign IPv6 addresses to interfaces - * (which is NOT recommended) must now ensure that link-local addresses carry - * the netif's zone. See the new ip6_zone.h header file for more information and - * relevant macros. For now it is still possible to turn off scopes support - * through the new LWIP_IPV6_SCOPES option. When upgrading an implementation that - * uses the core API directly, it is highly recommended to enable - * LWIP_IPV6_SCOPES_DEBUG at least for a while, to ensure e.g. proper address - * initialization. - */ -#if !defined LWIP_IPV6_SCOPES || defined __DOXYGEN__ -#define LWIP_IPV6_SCOPES (LWIP_IPV6 && !LWIP_SINGLE_NETIF) -#endif - -/** - * LWIP_IPV6_SCOPES_DEBUG==1: Perform run-time checks to verify that addresses - * are properly zoned (see ip6_zone.h on what that means) where it matters. - * Enabling this setting is highly recommended when upgrading from an existing - * installation that is not yet scope-aware; otherwise it may be too expensive. - */ -#if !defined LWIP_IPV6_SCOPES_DEBUG || defined __DOXYGEN__ -#define LWIP_IPV6_SCOPES_DEBUG 0 -#endif - -/** - * LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif. - */ -#if !defined LWIP_IPV6_NUM_ADDRESSES || defined __DOXYGEN__ -#define LWIP_IPV6_NUM_ADDRESSES 3 -#endif - -/** - * LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs - */ -#if !defined LWIP_IPV6_FORWARD || defined __DOXYGEN__ -#define LWIP_IPV6_FORWARD 0 -#endif - -/** - * LWIP_IPV6_FRAG==1: Fragment outgoing IPv6 packets that are too big. - */ -#if !defined LWIP_IPV6_FRAG || defined __DOXYGEN__ -#define LWIP_IPV6_FRAG 1 -#endif - -/** - * LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented - */ -#if !defined LWIP_IPV6_REASS || defined __DOXYGEN__ -#define LWIP_IPV6_REASS LWIP_IPV6 -#endif - -/** - * LWIP_IPV6_SEND_ROUTER_SOLICIT==1: Send router solicitation messages during - * network startup. - */ -#if !defined LWIP_IPV6_SEND_ROUTER_SOLICIT || defined __DOXYGEN__ -#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 -#endif - -/** - * LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862. - */ -#if !defined LWIP_IPV6_AUTOCONFIG || defined __DOXYGEN__ -#define LWIP_IPV6_AUTOCONFIG LWIP_IPV6 -#endif - -/** - * LWIP_IPV6_ADDRESS_LIFETIMES==1: Keep valid and preferred lifetimes for each - * IPv6 address. Required for LWIP_IPV6_AUTOCONFIG. May still be enabled - * otherwise, in which case the application may assign address lifetimes with - * the appropriate macros. Addresses with no lifetime are assumed to be static. - * If this option is disabled, all addresses are assumed to be static. - */ -#if !defined LWIP_IPV6_ADDRESS_LIFETIMES || defined __DOXYGEN__ -#define LWIP_IPV6_ADDRESS_LIFETIMES LWIP_IPV6_AUTOCONFIG -#endif - -/** - * LWIP_IPV6_DUP_DETECT_ATTEMPTS=[0..7]: Number of duplicate address detection attempts. - */ -#if !defined LWIP_IPV6_DUP_DETECT_ATTEMPTS || defined __DOXYGEN__ -#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 -#endif -/** - * @} - */ - -/** - * @defgroup lwip_opts_icmp6 ICMP6 - * @ingroup lwip_opts_ipv6 - * @{ - */ -/** - * LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC) - */ -#if !defined LWIP_ICMP6 || defined __DOXYGEN__ -#define LWIP_ICMP6 LWIP_IPV6 -#endif - -/** - * LWIP_ICMP6_DATASIZE: bytes from original packet to send back in - * ICMPv6 error messages. - */ -#if !defined LWIP_ICMP6_DATASIZE || defined __DOXYGEN__ -#define LWIP_ICMP6_DATASIZE 8 -#endif - -/** - * LWIP_ICMP6_HL: default hop limit for ICMPv6 messages - */ -#if !defined LWIP_ICMP6_HL || defined __DOXYGEN__ -#define LWIP_ICMP6_HL 255 -#endif -/** - * @} - */ - -/** - * @defgroup lwip_opts_mld6 Multicast listener discovery - * @ingroup lwip_opts_ipv6 - * @{ - */ -/** - * LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol. - * If LWIP_IPV6 is enabled but this setting is disabled, the MAC layer must - * indiscriminately pass all inbound IPv6 multicast traffic to lwIP. - */ -#if !defined LWIP_IPV6_MLD || defined __DOXYGEN__ -#define LWIP_IPV6_MLD LWIP_IPV6 -#endif - -/** - * MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast groups that can be joined. - * There must be enough groups so that each netif can join the solicited-node - * multicast group for each of its local addresses, plus one for MDNS if - * applicable, plus any number of groups to be joined on UDP sockets. - */ -#if !defined MEMP_NUM_MLD6_GROUP || defined __DOXYGEN__ -#define MEMP_NUM_MLD6_GROUP 4 -#endif -/** - * @} - */ - -/** - * @defgroup lwip_opts_nd6 Neighbor discovery - * @ingroup lwip_opts_ipv6 - * @{ - */ -/** - * LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address - * is being resolved. - */ -#if !defined LWIP_ND6_QUEUEING || defined __DOXYGEN__ -#define LWIP_ND6_QUEUEING LWIP_IPV6 -#endif - -/** - * MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution. - */ -#if !defined MEMP_NUM_ND6_QUEUE || defined __DOXYGEN__ -#define MEMP_NUM_ND6_QUEUE 20 -#endif - -/** - * LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache - */ -#if !defined LWIP_ND6_NUM_NEIGHBORS || defined __DOXYGEN__ -#define LWIP_ND6_NUM_NEIGHBORS 10 -#endif - -/** - * LWIP_ND6_NUM_DESTINATIONS: number of entries in IPv6 destination cache - */ -#if !defined LWIP_ND6_NUM_DESTINATIONS || defined __DOXYGEN__ -#define LWIP_ND6_NUM_DESTINATIONS 10 -#endif - -/** - * LWIP_ND6_NUM_PREFIXES: number of entries in IPv6 on-link prefixes cache - */ -#if !defined LWIP_ND6_NUM_PREFIXES || defined __DOXYGEN__ -#define LWIP_ND6_NUM_PREFIXES 5 -#endif - -/** - * LWIP_ND6_NUM_ROUTERS: number of entries in IPv6 default router cache - */ -#if !defined LWIP_ND6_NUM_ROUTERS || defined __DOXYGEN__ -#define LWIP_ND6_NUM_ROUTERS 3 -#endif - -/** - * LWIP_ND6_MAX_MULTICAST_SOLICIT: max number of multicast solicit messages to send - * (neighbor solicit and router solicit) - */ -#if !defined LWIP_ND6_MAX_MULTICAST_SOLICIT || defined __DOXYGEN__ -#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 -#endif - -/** - * LWIP_ND6_MAX_UNICAST_SOLICIT: max number of unicast neighbor solicitation messages - * to send during neighbor reachability detection. - */ -#if !defined LWIP_ND6_MAX_UNICAST_SOLICIT || defined __DOXYGEN__ -#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 -#endif - -/** - * Unused: See ND RFC (time in milliseconds). - */ -#if !defined LWIP_ND6_MAX_ANYCAST_DELAY_TIME || defined __DOXYGEN__ -#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 -#endif - -/** - * Unused: See ND RFC - */ -#if !defined LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT || defined __DOXYGEN__ -#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 -#endif - -/** - * LWIP_ND6_REACHABLE_TIME: default neighbor reachable time (in milliseconds). - * May be updated by router advertisement messages. - */ -#if !defined LWIP_ND6_REACHABLE_TIME || defined __DOXYGEN__ -#define LWIP_ND6_REACHABLE_TIME 30000 -#endif - -/** - * LWIP_ND6_RETRANS_TIMER: default retransmission timer for solicitation messages - */ -#if !defined LWIP_ND6_RETRANS_TIMER || defined __DOXYGEN__ -#define LWIP_ND6_RETRANS_TIMER 1000 -#endif - -/** - * LWIP_ND6_DELAY_FIRST_PROBE_TIME: Delay before first unicast neighbor solicitation - * message is sent, during neighbor reachability detection. - */ -#if !defined LWIP_ND6_DELAY_FIRST_PROBE_TIME || defined __DOXYGEN__ -#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 -#endif - -/** - * LWIP_ND6_ALLOW_RA_UPDATES==1: Allow Router Advertisement messages to update - * Reachable time and retransmission timers, and netif MTU. - */ -#if !defined LWIP_ND6_ALLOW_RA_UPDATES || defined __DOXYGEN__ -#define LWIP_ND6_ALLOW_RA_UPDATES 1 -#endif - -/** - * LWIP_ND6_TCP_REACHABILITY_HINTS==1: Allow TCP to provide Neighbor Discovery - * with reachability hints for connected destinations. This helps avoid sending - * unicast neighbor solicitation messages. - */ -#if !defined LWIP_ND6_TCP_REACHABILITY_HINTS || defined __DOXYGEN__ -#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 -#endif - -/** - * LWIP_ND6_RDNSS_MAX_DNS_SERVERS > 0: Use IPv6 Router Advertisement Recursive - * DNS Server Option (as per RFC 6106) to copy a defined maximum number of DNS - * servers to the DNS module. - */ -#if !defined LWIP_ND6_RDNSS_MAX_DNS_SERVERS || defined __DOXYGEN__ -#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 -#endif -/** - * @} - */ - -/** - * @defgroup lwip_opts_dhcpv6 DHCPv6 - * @ingroup lwip_opts_ipv6 - * @{ - */ -/** - * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful/stateless address autoconfiguration. - */ -#if !defined LWIP_IPV6_DHCP6 || defined __DOXYGEN__ -#define LWIP_IPV6_DHCP6 0 -#endif - -/** - * LWIP_IPV6_DHCP6_STATEFUL==1: enable DHCPv6 stateful address autoconfiguration. - * (not supported, yet!) - */ -#if !defined LWIP_IPV6_DHCP6_STATEFUL || defined __DOXYGEN__ -#define LWIP_IPV6_DHCP6_STATEFUL 0 -#endif - -/** - * LWIP_IPV6_DHCP6_STATELESS==1: enable DHCPv6 stateless address autoconfiguration. - */ -#if !defined LWIP_IPV6_DHCP6_STATELESS || defined __DOXYGEN__ -#define LWIP_IPV6_DHCP6_STATELESS LWIP_IPV6_DHCP6 -#endif - -/** - * LWIP_DHCP6_GETS_NTP==1: Request NTP servers via DHCPv6. For each - * response packet, a callback is called, which has to be provided by the port: - * void dhcp6_set_ntp_servers(u8_t num_ntp_servers, ip_addr_t* ntp_server_addrs); -*/ -#if !defined LWIP_DHCP6_GET_NTP_SRV || defined __DOXYGEN__ -#define LWIP_DHCP6_GET_NTP_SRV 0 -#endif - -/** - * The maximum of NTP servers requested - */ -#if !defined LWIP_DHCP6_MAX_NTP_SERVERS || defined __DOXYGEN__ -#define LWIP_DHCP6_MAX_NTP_SERVERS 1 -#endif - -/** - * LWIP_DHCP6_MAX_DNS_SERVERS > 0: Request DNS servers via DHCPv6. - * DNS servers received in the response are passed to DNS via @ref dns_setserver() - * (up to the maximum limit defined here). - */ -#if !defined LWIP_DHCP6_MAX_DNS_SERVERS || defined __DOXYGEN__ -#define LWIP_DHCP6_MAX_DNS_SERVERS DNS_MAX_SERVERS -#endif -/** - * @} - */ - -/* - --------------------------------------- - ---------- Hook options --------------- - --------------------------------------- -*/ - -/** - * @defgroup lwip_opts_hooks Hooks - * @ingroup lwip_opts_infrastructure - * Hooks are undefined by default, define them to a function if you need them. - * @{ - */ - -/** - * LWIP_HOOK_FILENAME: Custom filename to \#include in files that provide hooks. - * Declare your hook function prototypes in there, you may also \#include all headers - * providing data types that are need in this file. - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_FILENAME "path/to/my/lwip_hooks.h" -#endif - -/** - * LWIP_HOOK_TCP_ISN: - * Hook for generation of the Initial Sequence Number (ISN) for a new TCP - * connection. The default lwIP ISN generation algorithm is very basic and may - * allow for TCP spoofing attacks. This hook provides the means to implement - * the standardized ISN generation algorithm from RFC 6528 (see contrib/adons/tcp_isn), - * or any other desired algorithm as a replacement. - * Called from tcp_connect() and tcp_listen_input() when an ISN is needed for - * a new TCP connection, if TCP support (@ref LWIP_TCP) is enabled.\n - * Signature:\code{.c} - * u32_t my_hook_tcp_isn(const ip_addr_t* local_ip, u16_t local_port, const ip_addr_t* remote_ip, u16_t remote_port); - * \endcode - * - it may be necessary to use "struct ip_addr" (ip4_addr, ip6_addr) instead of "ip_addr_t" in function declarations\n - * Arguments: - * - local_ip: pointer to the local IP address of the connection - * - local_port: local port number of the connection (host-byte order) - * - remote_ip: pointer to the remote IP address of the connection - * - remote_port: remote port number of the connection (host-byte order)\n - * Return value: - * - the 32-bit Initial Sequence Number to use for the new TCP connection. - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_TCP_ISN(local_ip, local_port, remote_ip, remote_port) -#endif - -/** - * LWIP_HOOK_TCP_INPACKET_PCB: - * Hook for intercepting incoming packets before they are passed to a pcb. This - * allows updating some state or even dropping a packet. - * Signature:\code{.c} - * err_t my_hook_tcp_inpkt(struct tcp_pcb *pcb, struct tcp_hdr *hdr, u16_t optlen, u16_t opt1len, u8_t *opt2, struct pbuf *p); - * \endcode - * Arguments: - * - pcb: tcp_pcb selected for input of this packet (ATTENTION: this may be - * struct tcp_pcb_listen if pcb->state == LISTEN) - * - hdr: pointer to tcp header (ATTENTION: tcp options may not be in one piece!) - * - optlen: tcp option length - * - opt1len: tcp option length 1st part - * - opt2: if this is != NULL, tcp options are split among 2 pbufs. In that case, - * options start at right after the tcp header ('(u8_t*)(hdr + 1)') for - * the first 'opt1len' bytes and the rest starts at 'opt2'. opt2len can - * be simply calculated: 'opt2len = optlen - opt1len;' - * - p: input packet, p->payload points to application data (that's why tcp hdr - * and options are passed in seperately) - * Return value: - * - ERR_OK: continue input of this packet as normal - * - != ERR_OK: drop this packet for input (don't continue input processing) - * - * ATTENTION: don't call any tcp api functions that might change tcp state (pcb - * state or any pcb lists) from this callback! - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_TCP_INPACKET_PCB(pcb, hdr, optlen, opt1len, opt2, p) -#endif - -/** - * LWIP_HOOK_TCP_OUT_TCPOPT_LENGTH: - * Hook for increasing the size of the options allocated with a tcp header. - * Together with LWIP_HOOK_TCP_OUT_ADD_TCPOPTS, this can be used to add custom - * options to outgoing tcp segments. - * Signature:\code{.c} - * u8_t my_hook_tcp_out_tcpopt_length(const struct tcp_pcb *pcb, u8_t internal_option_length); - * \endcode - * Arguments: - * - pcb: tcp_pcb that transmits (ATTENTION: this may be NULL or - * struct tcp_pcb_listen if pcb->state == LISTEN) - * - internal_option_length: tcp option length used by the stack internally - * Return value: - * - a number of bytes to allocate for tcp options (internal_option_length <= ret <= 40) - * - * ATTENTION: don't call any tcp api functions that might change tcp state (pcb - * state or any pcb lists) from this callback! - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_TCP_OUT_TCPOPT_LENGTH(pcb, internal_len) -#endif - -/** - * LWIP_HOOK_TCP_OUT_ADD_TCPOPTS: - * Hook for adding custom options to outgoing tcp segments. - * Space for these custom options has to be reserved via LWIP_HOOK_TCP_OUT_TCPOPT_LENGTH. - * Signature:\code{.c} - * u32_t *my_hook_tcp_out_add_tcpopts(struct pbuf *p, struct tcp_hdr *hdr, const struct tcp_pcb *pcb, u32_t *opts); - * \endcode - * Arguments: - * - p: output packet, p->payload pointing to tcp header, data follows - * - hdr: tcp header - * - pcb: tcp_pcb that transmits (ATTENTION: this may be NULL or - * struct tcp_pcb_listen if pcb->state == LISTEN) - * - opts: pointer where to add the custom options (there may already be options - * between the header and these) - * Return value: - * - pointer pointing directly after the inserted options - * - * ATTENTION: don't call any tcp api functions that might change tcp state (pcb - * state or any pcb lists) from this callback! - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_TCP_OUT_ADD_TCPOPTS(p, hdr, pcb, opts) -#endif - -/** - * LWIP_HOOK_IP4_INPUT(pbuf, input_netif): - * Called from ip_input() (IPv4) - * Signature:\code{.c} - * int my_hook(struct pbuf *pbuf, struct netif *input_netif); - * \endcode - * Arguments: - * - pbuf: received struct pbuf passed to ip_input() - * - input_netif: struct netif on which the packet has been received - * Return values: - * - 0: Hook has not consumed the packet, packet is processed as normal - * - != 0: Hook has consumed the packet. - * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook - * (i.e. free it when done). - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_IP4_INPUT(pbuf, input_netif) -#endif - -/** - * LWIP_HOOK_IP4_ROUTE(dest): - * Called from ip_route() (IPv4) - * Signature:\code{.c} - * struct netif *my_hook(const ip4_addr_t *dest); - * \endcode - * Arguments: - * - dest: destination IPv4 address - * Returns values: - * - the destination netif - * - NULL if no destination netif is found. In that case, ip_route() continues as normal. - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_IP4_ROUTE() -#endif - -/** - * LWIP_HOOK_IP4_ROUTE_SRC(src, dest): - * Source-based routing for IPv4 - called from ip_route() (IPv4) - * Signature:\code{.c} - * struct netif *my_hook(const ip4_addr_t *src, const ip4_addr_t *dest); - * \endcode - * Arguments: - * - src: local/source IPv4 address - * - dest: destination IPv4 address - * Returns values: - * - the destination netif - * - NULL if no destination netif is found. In that case, ip_route() continues as normal. - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_IP4_ROUTE_SRC(src, dest) -#endif - -/** - * LWIP_HOOK_IP4_CANFORWARD(src, dest): - * Check if an IPv4 can be forwarded - called from: - * ip4_input() -> ip4_forward() -> ip4_canforward() (IPv4) - * - source address is available via ip4_current_src_addr() - * - calling an output function in this context (e.g. multicast router) is allowed - * Signature:\code{.c} - * int my_hook(struct pbuf *p, u32_t dest_addr_hostorder); - * \endcode - * Arguments: - * - p: packet to forward - * - dest: destination IPv4 address - * Returns values: - * - 1: forward - * - 0: don't forward - * - -1: no decision. In that case, ip4_canforward() continues as normal. - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_IP4_CANFORWARD(src, dest) -#endif - -/** - * LWIP_HOOK_ETHARP_GET_GW(netif, dest): - * Called from etharp_output() (IPv4) - * Signature:\code{.c} - * const ip4_addr_t *my_hook(struct netif *netif, const ip4_addr_t *dest); - * \endcode - * Arguments: - * - netif: the netif used for sending - * - dest: the destination IPv4 address - * Return values: - * - the IPv4 address of the gateway to handle the specified destination IPv4 address - * - NULL, in which case the netif's default gateway is used - * - * The returned address MUST be directly reachable on the specified netif! - * This function is meant to implement advanced IPv4 routing together with - * LWIP_HOOK_IP4_ROUTE(). The actual routing/gateway table implementation is - * not part of lwIP but can e.g. be hidden in the netif's state argument. -*/ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_ETHARP_GET_GW(netif, dest) -#endif - -/** - * LWIP_HOOK_IP6_INPUT(pbuf, input_netif): - * Called from ip6_input() (IPv6) - * Signature:\code{.c} - * int my_hook(struct pbuf *pbuf, struct netif *input_netif); - * \endcode - * Arguments: - * - pbuf: received struct pbuf passed to ip6_input() - * - input_netif: struct netif on which the packet has been received - * Return values: - * - 0: Hook has not consumed the packet, packet is processed as normal - * - != 0: Hook has consumed the packet. - * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook - * (i.e. free it when done). - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_IP6_INPUT(pbuf, input_netif) -#endif - -/** - * LWIP_HOOK_IP6_ROUTE(src, dest): - * Called from ip_route() (IPv6) - * Signature:\code{.c} - * struct netif *my_hook(const ip6_addr_t *dest, const ip6_addr_t *src); - * \endcode - * Arguments: - * - src: source IPv6 address - * - dest: destination IPv6 address - * Return values: - * - the destination netif - * - NULL if no destination netif is found. In that case, ip6_route() continues as normal. - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_IP6_ROUTE(src, dest) -#endif - -/** - * LWIP_HOOK_ND6_GET_GW(netif, dest): - * Called from nd6_get_next_hop_entry() (IPv6) - * Signature:\code{.c} - * const ip6_addr_t *my_hook(struct netif *netif, const ip6_addr_t *dest); - * \endcode - * Arguments: - * - netif: the netif used for sending - * - dest: the destination IPv6 address - * Return values: - * - the IPv6 address of the next hop to handle the specified destination IPv6 address - * - NULL, in which case a NDP-discovered router is used instead - * - * The returned address MUST be directly reachable on the specified netif! - * This function is meant to implement advanced IPv6 routing together with - * LWIP_HOOK_IP6_ROUTE(). The actual routing/gateway table implementation is - * not part of lwIP but can e.g. be hidden in the netif's state argument. -*/ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_ND6_GET_GW(netif, dest) -#endif - -/** - * LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr): - * Called from ethernet_input() if VLAN support is enabled - * Signature:\code{.c} - * int my_hook(struct netif *netif, struct eth_hdr *eth_hdr, struct eth_vlan_hdr *vlan_hdr); - * \endcode - * Arguments: - * - netif: struct netif on which the packet has been received - * - eth_hdr: struct eth_hdr of the packet - * - vlan_hdr: struct eth_vlan_hdr of the packet - * Return values: - * - 0: Packet must be dropped. - * - != 0: Packet must be accepted. - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr) -#endif - -/** - * LWIP_HOOK_VLAN_SET: - * Hook can be used to set prio_vid field of vlan_hdr. If you need to store data - * on per-netif basis to implement this callback, see @ref netif_cd. - * Called from ethernet_output() if VLAN support (@ref ETHARP_SUPPORT_VLAN) is enabled.\n - * Signature:\code{.c} - * s32_t my_hook_vlan_set(struct netif* netif, struct pbuf* pbuf, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type);\n - * \endcode - * Arguments: - * - netif: struct netif that the packet will be sent through - * - p: struct pbuf packet to be sent - * - src: source eth address - * - dst: destination eth address - * - eth_type: ethernet type to packet to be sent\n - * - * - * Return values: - * - <0: Packet shall not contain VLAN header. - * - 0 <= return value <= 0xFFFF: Packet shall contain VLAN header. Return value is prio_vid in host byte order. - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type) -#endif - -/** - * LWIP_HOOK_MEMP_AVAILABLE(memp_t_type): - * Called from memp_free() when a memp pool was empty and an item is now available - * Signature:\code{.c} - * void my_hook(memp_t type); - * \endcode - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_MEMP_AVAILABLE(memp_t_type) -#endif - -/** - * LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif): - * Called from ethernet_input() when an unknown eth type is encountered. - * Signature:\code{.c} - * err_t my_hook(struct pbuf* pbuf, struct netif* netif); - * \endcode - * Arguments: - * - p: rx packet with unknown eth type - * - netif: netif on which the packet has been received - * Return values: - * - ERR_OK if packet is accepted (hook function now owns the pbuf) - * - any error code otherwise (pbuf is freed) - * - * Payload points to ethernet header! - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif) -#endif - -/** - * LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, state, msg, msg_type, options_len_ptr): - * Called from various dhcp functions when sending a DHCP message. - * This hook is called just before the DHCP message trailer is added, so the - * options are at the end of a DHCP message. - * Signature:\code{.c} - * void my_hook(struct netif *netif, struct dhcp *dhcp, u8_t state, struct dhcp_msg *msg, - * u8_t msg_type, u16_t *options_len_ptr); - * \endcode - * Arguments: - * - netif: struct netif that the packet will be sent through - * - dhcp: struct dhcp on that netif - * - state: current dhcp state (dhcp_state_enum_t as an u8_t) - * - msg: struct dhcp_msg that will be sent - * - msg_type: dhcp message type to be sent (u8_t) - * - options_len_ptr: pointer to the current length of options in the dhcp_msg "msg" - * (must be increased when options are added!) - * - * Options need to appended like this: - * LWIP_ASSERT("dhcp option overflow", *options_len_ptr + option_len + 2 <= DHCP_OPTIONS_LEN); - * msg->options[(*options_len_ptr)++] = <option_number>; - * msg->options[(*options_len_ptr)++] = <option_len>; - * msg->options[(*options_len_ptr)++] = <option_bytes>; - * [...] - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, state, msg, msg_type, options_len_ptr) -#endif - -/** - * LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, option_value_offset): - * Called from dhcp_parse_reply when receiving a DHCP message. - * This hook is called for every option in the received message that is not handled internally. - * Signature:\code{.c} - * void my_hook(struct netif *netif, struct dhcp *dhcp, u8_t state, struct dhcp_msg *msg, - * u8_t msg_type, u8_t option, u8_t option_len, struct pbuf *pbuf, u16_t option_value_offset); - * \endcode - * Arguments: - * - netif: struct netif that the packet will be sent through - * - dhcp: struct dhcp on that netif - * - state: current dhcp state (dhcp_state_enum_t as an u8_t) - * - msg: struct dhcp_msg that was received - * - msg_type: dhcp message type received (u8_t, ATTENTION: only valid after - * the message type option has been parsed!) - * - option: option value (u8_t) - * - len: option data length (u8_t) - * - pbuf: pbuf where option data is contained - * - option_value_offset: offset in pbuf where option data begins - * - * A nice way to get the option contents is pbuf_get_contiguous(): - * u8_t buf[32]; - * u8_t *ptr = (u8_t*)pbuf_get_contiguous(p, buf, sizeof(buf), LWIP_MIN(option_len, sizeof(buf)), offset); - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, offset) -#endif - -/** - * LWIP_HOOK_DHCP6_APPEND_OPTIONS(netif, dhcp6, state, msg, msg_type, options_len_ptr, max_len): - * Called from various dhcp6 functions when sending a DHCP6 message. - * This hook is called just before the DHCP6 message is sent, so the - * options are at the end of a DHCP6 message. - * Signature:\code{.c} - * void my_hook(struct netif *netif, struct dhcp6 *dhcp, u8_t state, struct dhcp6_msg *msg, - * u8_t msg_type, u16_t *options_len_ptr); - * \endcode - * Arguments: - * - netif: struct netif that the packet will be sent through - * - dhcp6: struct dhcp6 on that netif - * - state: current dhcp6 state (dhcp6_state_enum_t as an u8_t) - * - msg: struct dhcp6_msg that will be sent - * - msg_type: dhcp6 message type to be sent (u8_t) - * - options_len_ptr: pointer to the current length of options in the dhcp6_msg "msg" - * (must be increased when options are added!) - * - * Options need to appended like this: - * u8_t *options = (u8_t *)(msg + 1); - * LWIP_ASSERT("dhcp option overflow", sizeof(struct dhcp6_msg) + *options_len_ptr + newoptlen <= max_len); - * options[(*options_len_ptr)++] = <option_data>; - * [...] - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_DHCP6_APPEND_OPTIONS(netif, dhcp6, state, msg, msg_type, options_len_ptr, max_len) -#endif - -/** - * LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, err) - * Called from socket API to implement setsockopt() for options not provided by lwIP. - * Core lock is held when this hook is called. - * Signature:\code{.c} - * int my_hook(int s, struct lwip_sock *sock, int level, int optname, const void *optval, socklen_t optlen, int *err) - * \endcode - * Arguments: - * - s: socket file descriptor - * - sock: internal socket descriptor (see lwip/priv/sockets_priv.h) - * - level: protocol level at which the option resides - * - optname: option to set - * - optval: value to set - * - optlen: size of optval - * - err: output error - * Return values: - * - 0: Hook has not consumed the option, code continues as normal (to internal options) - * - != 0: Hook has consumed the option, 'err' is returned - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, err) -#endif - -/** - * LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, err) - * Called from socket API to implement getsockopt() for options not provided by lwIP. - * Core lock is held when this hook is called. - * Signature:\code{.c} - * int my_hook(int s, struct lwip_sock *sock, int level, int optname, void *optval, socklen_t *optlen, int *err) - * \endcode - * Arguments: - * - s: socket file descriptor - * - sock: internal socket descriptor (see lwip/priv/sockets_priv.h) - * - level: protocol level at which the option resides - * - optname: option to get - * - optval: value to get - * - optlen: size of optval - * - err: output error - * Return values: - * - 0: Hook has not consumed the option, code continues as normal (to internal options) - * - != 0: Hook has consumed the option, 'err' is returned - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, err) -#endif - -/** - * LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, addrtype, err) - * Called from netconn APIs (not usable with callback apps) allowing an - * external DNS resolver (which uses sequential API) to handle the query. - * Signature:\code{.c} - * int my_hook(const char *name, ip_addr_t *addr, u8_t addrtype, err_t *err) - * \endcode - * Arguments: - * - name: hostname to resolve - * - addr: output host address - * - addrtype: type of address to query - * - err: output error - * Return values: - * - 0: Hook has not consumed hostname query, query continues into DNS module - * - != 0: Hook has consumed the query - * - * err must also be checked to determine if the hook consumed the query, but - * the query failed - */ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, addrtype, err) -#endif -/** - * @} - */ - -/* - --------------------------------------- - ---------- Debugging options ---------- - --------------------------------------- -*/ -/** - * @defgroup lwip_opts_debugmsg Debug messages - * @ingroup lwip_opts_debug - * @{ - */ -/** - * 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. - * @see debugging_levels - */ -#if !defined LWIP_DBG_MIN_LEVEL || defined __DOXYGEN__ -#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. - * @see debugging_levels - */ -#if !defined LWIP_DBG_TYPES_ON || defined __DOXYGEN__ -#define LWIP_DBG_TYPES_ON LWIP_DBG_ON -#endif - -/** - * ETHARP_DEBUG: Enable debugging in etharp.c. - */ -#if !defined ETHARP_DEBUG || defined __DOXYGEN__ -#define ETHARP_DEBUG LWIP_DBG_OFF -#endif - -/** - * NETIF_DEBUG: Enable debugging in netif.c. - */ -#if !defined NETIF_DEBUG || defined __DOXYGEN__ -#define NETIF_DEBUG LWIP_DBG_OFF -#endif - -/** - * PBUF_DEBUG: Enable debugging in pbuf.c. - */ -#if !defined PBUF_DEBUG || defined __DOXYGEN__ -#define PBUF_DEBUG LWIP_DBG_OFF -#endif - -/** - * API_LIB_DEBUG: Enable debugging in api_lib.c. - */ -#if !defined API_LIB_DEBUG || defined __DOXYGEN__ -#define API_LIB_DEBUG LWIP_DBG_OFF -#endif - -/** - * API_MSG_DEBUG: Enable debugging in api_msg.c. - */ -#if !defined API_MSG_DEBUG || defined __DOXYGEN__ -#define API_MSG_DEBUG LWIP_DBG_OFF -#endif - -/** - * SOCKETS_DEBUG: Enable debugging in sockets.c. - */ -#if !defined SOCKETS_DEBUG || defined __DOXYGEN__ -#define SOCKETS_DEBUG LWIP_DBG_OFF -#endif - -/** - * ICMP_DEBUG: Enable debugging in icmp.c. - */ -#if !defined ICMP_DEBUG || defined __DOXYGEN__ -#define ICMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * IGMP_DEBUG: Enable debugging in igmp.c. - */ -#if !defined IGMP_DEBUG || defined __DOXYGEN__ -#define IGMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * INET_DEBUG: Enable debugging in inet.c. - */ -#if !defined INET_DEBUG || defined __DOXYGEN__ -#define INET_DEBUG LWIP_DBG_OFF -#endif - -/** - * IP_DEBUG: Enable debugging for IP. - */ -#if !defined IP_DEBUG || defined __DOXYGEN__ -#define IP_DEBUG LWIP_DBG_OFF -#endif - -/** - * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. - */ -#if !defined IP_REASS_DEBUG || defined __DOXYGEN__ -#define IP_REASS_DEBUG LWIP_DBG_OFF -#endif - -/** - * RAW_DEBUG: Enable debugging in raw.c. - */ -#if !defined RAW_DEBUG || defined __DOXYGEN__ -#define RAW_DEBUG LWIP_DBG_OFF -#endif - -/** - * MEM_DEBUG: Enable debugging in mem.c. - */ -#if !defined MEM_DEBUG || defined __DOXYGEN__ -#define MEM_DEBUG LWIP_DBG_OFF -#endif - -/** - * MEMP_DEBUG: Enable debugging in memp.c. - */ -#if !defined MEMP_DEBUG || defined __DOXYGEN__ -#define MEMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * SYS_DEBUG: Enable debugging in sys.c. - */ -#if !defined SYS_DEBUG || defined __DOXYGEN__ -#define SYS_DEBUG LWIP_DBG_OFF -#endif - -/** - * TIMERS_DEBUG: Enable debugging in timers.c. - */ -#if !defined TIMERS_DEBUG || defined __DOXYGEN__ -#define TIMERS_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_DEBUG: Enable debugging for TCP. - */ -#if !defined TCP_DEBUG || defined __DOXYGEN__ -#define TCP_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. - */ -#if !defined TCP_INPUT_DEBUG || defined __DOXYGEN__ -#define TCP_INPUT_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. - */ -#if !defined TCP_FR_DEBUG || defined __DOXYGEN__ -#define TCP_FR_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit - * timeout. - */ -#if !defined TCP_RTO_DEBUG || defined __DOXYGEN__ -#define TCP_RTO_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. - */ -#if !defined TCP_CWND_DEBUG || defined __DOXYGEN__ -#define TCP_CWND_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. - */ -#if !defined TCP_WND_DEBUG || defined __DOXYGEN__ -#define TCP_WND_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. - */ -#if !defined TCP_OUTPUT_DEBUG || defined __DOXYGEN__ -#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. - */ -#if !defined TCP_RST_DEBUG || defined __DOXYGEN__ -#define TCP_RST_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. - */ -#if !defined TCP_QLEN_DEBUG || defined __DOXYGEN__ -#define TCP_QLEN_DEBUG LWIP_DBG_OFF -#endif - -/** - * UDP_DEBUG: Enable debugging in UDP. - */ -#if !defined UDP_DEBUG || defined __DOXYGEN__ -#define UDP_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCPIP_DEBUG: Enable debugging in tcpip.c. - */ -#if !defined TCPIP_DEBUG || defined __DOXYGEN__ -#define TCPIP_DEBUG LWIP_DBG_OFF -#endif - -/** - * SLIP_DEBUG: Enable debugging in slipif.c. - */ -#if !defined SLIP_DEBUG || defined __DOXYGEN__ -#define SLIP_DEBUG LWIP_DBG_OFF -#endif - -/** - * DHCP_DEBUG: Enable debugging in dhcp.c. - */ -#if !defined DHCP_DEBUG || defined __DOXYGEN__ -#define DHCP_DEBUG LWIP_DBG_OFF -#endif - -/** - * AUTOIP_DEBUG: Enable debugging in autoip.c. - */ -#if !defined AUTOIP_DEBUG || defined __DOXYGEN__ -#define AUTOIP_DEBUG LWIP_DBG_OFF -#endif - -/** - * DNS_DEBUG: Enable debugging for DNS. - */ -#if !defined DNS_DEBUG || defined __DOXYGEN__ -#define DNS_DEBUG LWIP_DBG_OFF -#endif - -/** - * IP6_DEBUG: Enable debugging for IPv6. - */ -#if !defined IP6_DEBUG || defined __DOXYGEN__ -#define IP6_DEBUG LWIP_DBG_OFF -#endif - -/** - * DHCP6_DEBUG: Enable debugging in dhcp6.c. - */ -#if !defined DHCP6_DEBUG || defined __DOXYGEN__ -#define DHCP6_DEBUG LWIP_DBG_OFF -#endif -/** - * @} - */ - -/** - * LWIP_TESTMODE: Changes to make unit test possible - */ -#if !defined LWIP_TESTMODE -#define LWIP_TESTMODE 0 -#endif - -/* - -------------------------------------------------- - ---------- Performance tracking options ---------- - -------------------------------------------------- -*/ -/** - * @defgroup lwip_opts_perf Performance - * @ingroup lwip_opts_debug - * @{ - */ -/** - * LWIP_PERF: Enable performance testing for lwIP - * (if enabled, arch/perf.h is included) - */ -#if !defined LWIP_PERF || defined __DOXYGEN__ -#define LWIP_PERF 0 -#endif -/** - * @} - */ - -#endif /* LWIP_HDR_OPT_H */ diff --git a/core/c/include/lwip/pbuf.h b/core/c/include/lwip/pbuf.h deleted file mode 100755 index 328c772..0000000 --- a/core/c/include/lwip/pbuf.h +++ /dev/null @@ -1,322 +0,0 @@ -/** - * @file - * pbuf API - */ - -/* - * 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_HDR_PBUF_H -#define LWIP_HDR_PBUF_H - -#include "lwip/opt.h" -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** LWIP_SUPPORT_CUSTOM_PBUF==1: Custom pbufs behave much like their pbuf type - * but they are allocated by external code (initialised by calling - * pbuf_alloced_custom()) and when pbuf_free gives up their last reference, they - * are freed by calling pbuf_custom->custom_free_function(). - * Currently, the pbuf_custom code is only needed for one specific configuration - * of IP_FRAG, unless required by external driver/application code. */ -#ifndef LWIP_SUPPORT_CUSTOM_PBUF -#define LWIP_SUPPORT_CUSTOM_PBUF ((IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG)) -#endif - -/** @ingroup pbuf - * PBUF_NEEDS_COPY(p): return a boolean value indicating whether the given - * pbuf needs to be copied in order to be kept around beyond the current call - * stack without risking being corrupted. The default setting provides safety: - * it will make a copy iof any pbuf chain that does not consist entirely of - * PBUF_ROM type pbufs. For setups with zero-copy support, it may be redefined - * to evaluate to true in all cases, for example. However, doing so also has an - * effect on the application side: any buffers that are *not* copied must also - * *not* be reused by the application after passing them to lwIP. For example, - * when setting PBUF_NEEDS_COPY to (0), after using udp_send() with a PBUF_RAM - * pbuf, the application must free the pbuf immediately, rather than reusing it - * for other purposes. For more background information on this, see tasks #6735 - * and #7896, and bugs #11400 and #49914. */ -#ifndef PBUF_NEEDS_COPY -#define PBUF_NEEDS_COPY(p) ((p)->type_internal & PBUF_TYPE_FLAG_DATA_VOLATILE) -#endif /* PBUF_NEEDS_COPY */ - -/* @todo: We need a mechanism to prevent wasting memory in every pbuf - (TCP vs. UDP, IPv4 vs. IPv6: UDP/IPv4 packets may waste up to 28 bytes) */ - -#define PBUF_TRANSPORT_HLEN 20 -#if LWIP_IPV6 -#define PBUF_IP_HLEN 40 -#else -#define PBUF_IP_HLEN 20 -#endif - -/** - * @ingroup pbuf - * Enumeration of pbuf layers - */ -typedef enum { - /** Includes spare room for transport layer header, e.g. UDP header. - * Use this if you intend to pass the pbuf to functions like udp_send(). - */ - PBUF_TRANSPORT = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN, - /** Includes spare room for IP header. - * Use this if you intend to pass the pbuf to functions like raw_send(). - */ - PBUF_IP = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN, - /** Includes spare room for link layer header (ethernet header). - * Use this if you intend to pass the pbuf to functions like ethernet_output(). - * @see PBUF_LINK_HLEN - */ - PBUF_LINK = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN, - /** Includes spare room for additional encapsulation header before ethernet - * headers (e.g. 802.11). - * Use this if you intend to pass the pbuf to functions like netif->linkoutput(). - * @see PBUF_LINK_ENCAPSULATION_HLEN - */ - PBUF_RAW_TX = PBUF_LINK_ENCAPSULATION_HLEN, - /** Use this for input packets in a netif driver when calling netif->input() - * in the most common case - ethernet-layer netif driver. */ - PBUF_RAW = 0 -} pbuf_layer; - - -/* Base flags for pbuf_type definitions: */ - -/** Indicates that the payload directly follows the struct pbuf. - * This makes @ref pbuf_header work in both directions. */ -#define PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS 0x80 -/** Indicates the data stored in this pbuf can change. If this pbuf needs - * to be queued, it must be copied/duplicated. */ -#define PBUF_TYPE_FLAG_DATA_VOLATILE 0x40 -/** 4 bits are reserved for 16 allocation sources (e.g. heap, pool1, pool2, etc) - * Internally, we use: 0=heap, 1=MEMP_PBUF, 2=MEMP_PBUF_POOL -> 13 types free*/ -#define PBUF_TYPE_ALLOC_SRC_MASK 0x0F -/** Indicates this pbuf is used for RX (if not set, indicates use for TX). - * This information can be used to keep some spare RX buffers e.g. for - * receiving TCP ACKs to unblock a connection) */ -#define PBUF_ALLOC_FLAG_RX 0x0100 -/** Indicates the application needs the pbuf payload to be in one piece */ -#define PBUF_ALLOC_FLAG_DATA_CONTIGUOUS 0x0200 - -#define PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP 0x00 -#define PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF 0x01 -#define PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF_POOL 0x02 -/** First pbuf allocation type for applications */ -#define PBUF_TYPE_ALLOC_SRC_MASK_APP_MIN 0x03 -/** Last pbuf allocation type for applications */ -#define PBUF_TYPE_ALLOC_SRC_MASK_APP_MAX PBUF_TYPE_ALLOC_SRC_MASK - -/** - * @ingroup pbuf - * Enumeration of pbuf types - */ -typedef enum { - /** pbuf data is stored in RAM, used for TX mostly, struct pbuf and its payload - are allocated in one piece of contiguous memory (so the first payload byte - can be calculated from struct pbuf). - pbuf_alloc() allocates PBUF_RAM pbufs as unchained pbufs (although that might - change in future versions). - This should be used for all OUTGOING packets (TX).*/ - PBUF_RAM = (PBUF_ALLOC_FLAG_DATA_CONTIGUOUS | PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS | PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP), - /** pbuf data is stored in ROM, i.e. struct pbuf and its payload are located in - totally different memory areas. Since it points to ROM, payload does not - have to be copied when queued for transmission. */ - PBUF_ROM = PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF, - /** pbuf comes from the pbuf pool. Much like PBUF_ROM but payload might change - so it has to be duplicated when queued before transmitting, depending on - who has a 'ref' to it. */ - PBUF_REF = (PBUF_TYPE_FLAG_DATA_VOLATILE | PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF), - /** pbuf payload refers to RAM. This one comes from a pool and should be used - for RX. Payload can be chained (scatter-gather RX) but like PBUF_RAM, struct - pbuf and its payload are allocated in one piece of contiguous memory (so - the first payload byte can be calculated from struct pbuf). - Don't use this for TX, if the pool becomes empty e.g. because of TCP queuing, - you are unable to receive TCP acks! */ - PBUF_POOL = (PBUF_ALLOC_FLAG_RX | PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS | PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF_POOL) -} 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 calls pbuf_custom->custom_free_function() - when the last reference is released (plus custom PBUF_RAM cannot be trimmed) */ -#define PBUF_FLAG_IS_CUSTOM 0x02U -/** indicates this pbuf is UDP multicast to be looped back */ -#define PBUF_FLAG_MCASTLOOP 0x04U -/** indicates this pbuf was received as link-level broadcast */ -#define PBUF_FLAG_LLBCAST 0x08U -/** indicates this pbuf was received as link-level multicast */ -#define PBUF_FLAG_LLMCAST 0x10U -/** indicates this pbuf includes a TCP FIN flag */ -#define PBUF_FLAG_TCP_FIN 0x20U - -/** Main packet buffer struct */ -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; - - /** a bit field indicating pbuf type and allocation sources - (see PBUF_TYPE_FLAG_*, PBUF_ALLOC_FLAG_* and PBUF_TYPE_ALLOC_SRC_MASK) - */ - u8_t type_internal; - - /** 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. - */ - LWIP_PBUF_REF_T ref; - - /** For incoming packets, this contains the input netif's index */ - u8_t if_idx; -}; - - -/** Helper struct for const-correctness only. - * The only meaning of this one is to provide a const payload pointer - * for PBUF_ROM type. - */ -struct pbuf_rom { - /** next pbuf in singly linked pbuf chain */ - struct pbuf *next; - - /** pointer to the actual data in the buffer */ - const void *payload; -}; - -#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 */ - -/** 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 LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ -extern volatile u8_t pbuf_free_ooseq_pending; -void pbuf_free_ooseq(void); -/** When not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() - at regular intervals from main level to check if ooseq pbufs need to be - freed! */ -#define PBUF_CHECK_FREE_OOSEQ() do { if(pbuf_free_ooseq_pending) { \ - /* pbuf_alloc() reported PBUF_POOL to be empty -> try to free some \ - ooseq queued pbufs now */ \ - pbuf_free_ooseq(); }}while(0) -#else /* LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ */ - /* Otherwise declare an empty PBUF_CHECK_FREE_OOSEQ */ - #define PBUF_CHECK_FREE_OOSEQ() -#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ*/ - -/* 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); -struct pbuf *pbuf_alloc_reference(void *payload, u16_t length, pbuf_type type); -#if LWIP_SUPPORT_CUSTOM_PBUF -struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, - struct pbuf_custom *p, void *payload_mem, - u16_t payload_mem_len); -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ -void pbuf_realloc(struct pbuf *p, u16_t size); -#define pbuf_get_allocsrc(p) ((p)->type_internal & PBUF_TYPE_ALLOC_SRC_MASK) -#define pbuf_match_allocsrc(p, type) (pbuf_get_allocsrc(p) == ((type) & PBUF_TYPE_ALLOC_SRC_MASK)) -#define pbuf_match_type(p, type) pbuf_match_allocsrc(p, type) -u8_t pbuf_header(struct pbuf *p, s16_t header_size); -u8_t pbuf_header_force(struct pbuf *p, s16_t header_size); -u8_t pbuf_add_header(struct pbuf *p, size_t header_size_increment); -u8_t pbuf_add_header_force(struct pbuf *p, size_t header_size_increment); -u8_t pbuf_remove_header(struct pbuf *p, size_t header_size); -struct pbuf *pbuf_free_header(struct pbuf *q, u16_t size); -void pbuf_ref(struct pbuf *p); -u8_t pbuf_free(struct pbuf *p); -u16_t pbuf_clen(const struct pbuf *p); -void pbuf_cat(struct pbuf *head, struct pbuf *tail); -void pbuf_chain(struct pbuf *head, struct pbuf *tail); -struct pbuf *pbuf_dechain(struct pbuf *p); -err_t pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from); -u16_t pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset); -void *pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset); -err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); -err_t pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset); -struct pbuf *pbuf_skip(struct pbuf* in, u16_t in_offset, u16_t* out_offset); -struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer); -struct pbuf *pbuf_clone(pbuf_layer l, pbuf_type type, struct pbuf *p); -#if LWIP_CHECKSUM_ON_COPY -err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, - u16_t len, u16_t *chksum); -#endif /* LWIP_CHECKSUM_ON_COPY */ -#if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE -void pbuf_split_64k(struct pbuf *p, struct pbuf **rest); -#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ - -u8_t pbuf_get_at(const struct pbuf* p, u16_t offset); -int pbuf_try_get_at(const struct pbuf* p, u16_t offset); -void pbuf_put_at(struct pbuf* p, u16_t offset, u8_t data); -u16_t pbuf_memcmp(const struct pbuf* p, u16_t offset, const void* s2, u16_t n); -u16_t pbuf_memfind(const struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset); -u16_t pbuf_strstr(const struct pbuf* p, const char* substr); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PBUF_H */ diff --git a/core/c/include/lwip/priv/altcp_priv.h b/core/c/include/lwip/priv/altcp_priv.h deleted file mode 100755 index 381fc96..0000000 --- a/core/c/include/lwip/priv/altcp_priv.h +++ /dev/null @@ -1,146 +0,0 @@ -/** - * @file - * Application layered TCP connection API (to be used from TCPIP thread)\n - * This interface mimics the tcp callback API to the application while preventing - * direct linking (much like virtual functions). - * This way, an application can make use of other application layer protocols - * on top of TCP without knowing the details (e.g. TLS, proxy connection). - */ - -/* - * Copyright (c) 2017 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ -#ifndef LWIP_HDR_ALTCP_PRIV_H -#define LWIP_HDR_ALTCP_PRIV_H - -#include "lwip/opt.h" - -#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/altcp.h" -#include "lwip/ip_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct altcp_pcb *altcp_alloc(void); -void altcp_free(struct altcp_pcb *conn); - -/* Function prototypes for application layers */ -typedef void (*altcp_set_poll_fn)(struct altcp_pcb *conn, u8_t interval); -typedef void (*altcp_recved_fn)(struct altcp_pcb *conn, u16_t len); -typedef err_t (*altcp_bind_fn)(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port); -typedef err_t (*altcp_connect_fn)(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected); - -typedef struct altcp_pcb *(*altcp_listen_fn)(struct altcp_pcb *conn, u8_t backlog, err_t *err); - -typedef void (*altcp_abort_fn)(struct altcp_pcb *conn); -typedef err_t (*altcp_close_fn)(struct altcp_pcb *conn); -typedef err_t (*altcp_shutdown_fn)(struct altcp_pcb *conn, int shut_rx, int shut_tx); - -typedef err_t (*altcp_write_fn)(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags); -typedef err_t (*altcp_output_fn)(struct altcp_pcb *conn); - -typedef u16_t (*altcp_mss_fn)(struct altcp_pcb *conn); -typedef u16_t (*altcp_sndbuf_fn)(struct altcp_pcb *conn); -typedef u16_t (*altcp_sndqueuelen_fn)(struct altcp_pcb *conn); -typedef void (*altcp_nagle_disable_fn)(struct altcp_pcb *conn); -typedef void (*altcp_nagle_enable_fn)(struct altcp_pcb *conn); -typedef int (*altcp_nagle_disabled_fn)(struct altcp_pcb *conn); - -typedef void (*altcp_setprio_fn)(struct altcp_pcb *conn, u8_t prio); - -typedef void (*altcp_dealloc_fn)(struct altcp_pcb *conn); - -typedef err_t (*altcp_get_tcp_addrinfo_fn)(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port); -typedef ip_addr_t *(*altcp_get_ip_fn)(struct altcp_pcb *conn, int local); -typedef u16_t (*altcp_get_port_fn)(struct altcp_pcb *conn, int local); - -#ifdef LWIP_DEBUG -typedef enum tcp_state (*altcp_dbg_get_tcp_state_fn)(struct altcp_pcb *conn); -#endif - -struct altcp_functions { - altcp_set_poll_fn set_poll; - altcp_recved_fn recved; - altcp_bind_fn bind; - altcp_connect_fn connect; - altcp_listen_fn listen; - altcp_abort_fn abort; - altcp_close_fn close; - altcp_shutdown_fn shutdown; - altcp_write_fn write; - altcp_output_fn output; - altcp_mss_fn mss; - altcp_sndbuf_fn sndbuf; - altcp_sndqueuelen_fn sndqueuelen; - altcp_nagle_disable_fn nagle_disable; - altcp_nagle_enable_fn nagle_enable; - altcp_nagle_disabled_fn nagle_disabled; - altcp_setprio_fn setprio; - altcp_dealloc_fn dealloc; - altcp_get_tcp_addrinfo_fn addrinfo; - altcp_get_ip_fn getip; - altcp_get_port_fn getport; -#ifdef LWIP_DEBUG - altcp_dbg_get_tcp_state_fn dbg_get_tcp_state; -#endif -}; - -void altcp_default_set_poll(struct altcp_pcb *conn, u8_t interval); -void altcp_default_recved(struct altcp_pcb *conn, u16_t len); -err_t altcp_default_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port); -err_t altcp_default_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx); -err_t altcp_default_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags); -err_t altcp_default_output(struct altcp_pcb *conn); -u16_t altcp_default_mss(struct altcp_pcb *conn); -u16_t altcp_default_sndbuf(struct altcp_pcb *conn); -u16_t altcp_default_sndqueuelen(struct altcp_pcb *conn); -void altcp_default_nagle_disable(struct altcp_pcb *conn); -void altcp_default_nagle_enable(struct altcp_pcb *conn); -int altcp_default_nagle_disabled(struct altcp_pcb *conn); -void altcp_default_setprio(struct altcp_pcb *conn, u8_t prio); -void altcp_default_dealloc(struct altcp_pcb *conn); -err_t altcp_default_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port); -ip_addr_t *altcp_default_get_ip(struct altcp_pcb *conn, int local); -u16_t altcp_default_get_port(struct altcp_pcb *conn, int local); -#ifdef LWIP_DEBUG -enum tcp_state altcp_default_dbg_get_tcp_state(struct altcp_pcb *conn); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_ALTCP */ - -#endif /* LWIP_HDR_ALTCP_PRIV_H */ diff --git a/core/c/include/lwip/priv/api_msg.h b/core/c/include/lwip/priv/api_msg.h deleted file mode 100755 index 64c8763..0000000 --- a/core/c/include/lwip/priv/api_msg.h +++ /dev/null @@ -1,272 +0,0 @@ -/** - * @file - * netconn API lwIP internal implementations (do not use in application code) - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef LWIP_HDR_API_MSG_H -#define LWIP_HDR_API_MSG_H - -#include "lwip/opt.h" - -#include "lwip/arch.h" -#include "lwip/ip_addr.h" -#include "lwip/err.h" -#include "lwip/sys.h" -#include "lwip/igmp.h" -#include "lwip/api.h" -#include "lwip/priv/tcpip_priv.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_NETCONN || LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ -/* Note: Netconn API is always available when sockets are enabled - - * sockets are implemented on top of them */ - -#if LWIP_MPU_COMPATIBLE -#if LWIP_NETCONN_SEM_PER_THREAD -#define API_MSG_M_DEF_SEM(m) *m -#else -#define API_MSG_M_DEF_SEM(m) API_MSG_M_DEF(m) -#endif -#else /* LWIP_MPU_COMPATIBLE */ -#define API_MSG_M_DEF_SEM(m) API_MSG_M_DEF(m) -#endif /* LWIP_MPU_COMPATIBLE */ - -/* 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 { - /** 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 lwip_netconn_do_send */ - struct netbuf *b; - /** used for lwip_netconn_do_newconn */ - struct { - u8_t proto; - } n; - /** used for lwip_netconn_do_bind and lwip_netconn_do_connect */ - struct { - API_MSG_M_DEF_C(ip_addr_t, ipaddr); - u16_t port; - u8_t if_idx; - } bc; - /** used for lwip_netconn_do_getaddr */ - struct { - ip_addr_t API_MSG_M_DEF(ipaddr); - u16_t API_MSG_M_DEF(port); - u8_t local; - } ad; - /** used for lwip_netconn_do_write */ - struct { - /** current vector to write */ - const struct netvector *vector; - /** number of unwritten vectors */ - u16_t vector_cnt; - /** offset into current vector */ - size_t vector_off; - /** total length across vectors */ - size_t len; - /** offset into total length/output of bytes written when err == ERR_OK */ - size_t offset; - u8_t apiflags; -#if LWIP_SO_SNDTIMEO - u32_t time_started; -#endif /* LWIP_SO_SNDTIMEO */ - } w; - /** used for lwip_netconn_do_recv */ - struct { - size_t len; - } r; -#if LWIP_TCP - /** used for lwip_netconn_do_close (/shutdown) */ - struct { - u8_t shut; -#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER - u32_t time_started; -#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ - u8_t polls_left; -#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ - } sd; -#endif /* LWIP_TCP */ -#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) - /** used for lwip_netconn_do_join_leave_group */ - struct { - API_MSG_M_DEF_C(ip_addr_t, multiaddr); - API_MSG_M_DEF_C(ip_addr_t, netif_addr); - u8_t if_idx; - enum netconn_igmp join_or_leave; - } jl; -#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ -#if TCP_LISTEN_BACKLOG - struct { - u8_t backlog; - } lb; -#endif /* TCP_LISTEN_BACKLOG */ - } msg; -#if LWIP_NETCONN_SEM_PER_THREAD - sys_sem_t* op_completed_sem; -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ -}; - -#if LWIP_NETCONN_SEM_PER_THREAD -#define LWIP_API_MSG_SEM(msg) ((msg)->op_completed_sem) -#else /* LWIP_NETCONN_SEM_PER_THREAD */ -#define LWIP_API_MSG_SEM(msg) (&(msg)->conn->op_completed) -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ - - -#if LWIP_DNS -/** As lwip_netconn_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). - lwip_netconn_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 */ -#if LWIP_MPU_COMPATIBLE - char name[DNS_MAX_NAME_LENGTH]; -#else /* LWIP_MPU_COMPATIBLE */ - const char *name; -#endif /* LWIP_MPU_COMPATIBLE */ - /** The resolved address is stored here */ - ip_addr_t API_MSG_M_DEF(addr); -#if LWIP_IPV4 && LWIP_IPV6 - /** Type of resolve call */ - u8_t dns_addrtype; -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - /** This semaphore is posted when the name is resolved, the application thread - should wait on it. */ - sys_sem_t API_MSG_M_DEF_SEM(sem); - /** Errors are given back here */ - err_t API_MSG_M_DEF(err); -}; -#endif /* LWIP_DNS */ - -#if LWIP_NETCONN_FULLDUPLEX -int lwip_netconn_is_deallocated_msg(void *msg); -#endif -int lwip_netconn_is_err_msg(void *msg, err_t *err); -void lwip_netconn_do_newconn (void *m); -void lwip_netconn_do_delconn (void *m); -void lwip_netconn_do_bind (void *m); -void lwip_netconn_do_bind_if (void *m); -void lwip_netconn_do_connect (void *m); -void lwip_netconn_do_disconnect (void *m); -void lwip_netconn_do_listen (void *m); -void lwip_netconn_do_send (void *m); -void lwip_netconn_do_recv (void *m); -#if TCP_LISTEN_BACKLOG -void lwip_netconn_do_accepted (void *m); -#endif /* TCP_LISTEN_BACKLOG */ -void lwip_netconn_do_write (void *m); -void lwip_netconn_do_getaddr (void *m); -void lwip_netconn_do_close (void *m); -void lwip_netconn_do_shutdown (void *m); -#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) -void lwip_netconn_do_join_leave_group(void *m); -void lwip_netconn_do_join_leave_group_netif(void *m); -#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ - -#if LWIP_DNS -void lwip_netconn_do_gethostbyname(void *arg); -#endif /* LWIP_DNS */ - -struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); -void netconn_free(struct netconn *conn); - -#endif /* LWIP_NETCONN || LWIP_SOCKET */ - -#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ - -/* netifapi related lwIP internal definitions */ - -#if LWIP_MPU_COMPATIBLE -#define NETIFAPI_IPADDR_DEF(type, m) type m -#else /* LWIP_MPU_COMPATIBLE */ -#define NETIFAPI_IPADDR_DEF(type, m) const type * m -#endif /* LWIP_MPU_COMPATIBLE */ - -typedef void (*netifapi_void_fn)(struct netif *netif); -typedef err_t (*netifapi_errt_fn)(struct netif *netif); - -struct netifapi_msg { - struct tcpip_api_call_data call; - struct netif *netif; - union { - struct { -#if LWIP_IPV4 - NETIFAPI_IPADDR_DEF(ip4_addr_t, ipaddr); - NETIFAPI_IPADDR_DEF(ip4_addr_t, netmask); - NETIFAPI_IPADDR_DEF(ip4_addr_t, gw); -#endif /* LWIP_IPV4 */ - void *state; - netif_init_fn init; - netif_input_fn input; - } add; - struct { - netifapi_void_fn voidfunc; - netifapi_errt_fn errtfunc; - } common; - struct { -#if LWIP_MPU_COMPATIBLE - char name[NETIF_NAMESIZE]; -#else /* LWIP_MPU_COMPATIBLE */ - char *name; -#endif /* LWIP_MPU_COMPATIBLE */ - u8_t index; - } ifs; - } msg; -}; - -#endif /* LWIP_NETIF_API */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_API_MSG_H */ diff --git a/core/c/include/lwip/priv/mem_priv.h b/core/c/include/lwip/priv/mem_priv.h deleted file mode 100755 index 5abd9b5..0000000 --- a/core/c/include/lwip/priv/mem_priv.h +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file - * lwIP internal memory implementations (do not use in application code) - */ - -/* - * Copyright (c) 2018 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 - * - */ - -#ifndef LWIP_HDR_MEM_PRIV_H -#define LWIP_HDR_MEM_PRIV_H - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#include "lwip/mem.h" - -#if MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK -/* if MEM_OVERFLOW_CHECK or 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 MEM(P)_OVERFLOW_CHECK is >= 2, on every call to mem(p)_malloc or mem(p)_free, - * every single element in each pool/heap is checked! - * This is VERY SLOW but also very helpful. - * MEM_SANITY_REGION_BEFORE and MEM_SANITY_REGION_AFTER can be overridden in - * lwipopts.h to change the amount reserved for checking. */ -#ifndef MEM_SANITY_REGION_BEFORE -#define MEM_SANITY_REGION_BEFORE 16 -#endif /* MEM_SANITY_REGION_BEFORE*/ -#if MEM_SANITY_REGION_BEFORE > 0 -#define MEM_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SANITY_REGION_BEFORE) -#else -#define MEM_SANITY_REGION_BEFORE_ALIGNED 0 -#endif /* MEM_SANITY_REGION_BEFORE*/ -#ifndef MEM_SANITY_REGION_AFTER -#define MEM_SANITY_REGION_AFTER 16 -#endif /* MEM_SANITY_REGION_AFTER*/ -#if MEM_SANITY_REGION_AFTER > 0 -#define MEM_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SANITY_REGION_AFTER) -#else -#define MEM_SANITY_REGION_AFTER_ALIGNED 0 -#endif /* MEM_SANITY_REGION_AFTER*/ - -void mem_overflow_init_raw(void *p, size_t size); -void mem_overflow_check_raw(void *p, size_t size, const char *descr1, const char *descr2); - -#endif /* MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_MEMP_PRIV_H */ diff --git a/core/c/include/lwip/priv/memp_priv.h b/core/c/include/lwip/priv/memp_priv.h deleted file mode 100755 index f9930fd..0000000 --- a/core/c/include/lwip/priv/memp_priv.h +++ /dev/null @@ -1,161 +0,0 @@ -/** - * @file - * memory pools lwIP internal implementations (do not use in application code) - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#ifndef LWIP_HDR_MEMP_PRIV_H -#define LWIP_HDR_MEMP_PRIV_H - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#include "lwip/mem.h" -#include "lwip/priv/mem_priv.h" - -#if MEMP_OVERFLOW_CHECK - - -/* MEMP_SIZE: save space for struct memp and for sanity check */ -#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEM_SANITY_REGION_BEFORE_ALIGNED) -#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEM_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 */ - -#if !MEMP_MEM_MALLOC || MEMP_OVERFLOW_CHECK -struct memp { - struct memp *next; -#if MEMP_OVERFLOW_CHECK - const char *file; - int line; -#endif /* MEMP_OVERFLOW_CHECK */ -}; -#endif /* !MEMP_MEM_MALLOC || MEMP_OVERFLOW_CHECK */ - -#if MEM_USE_POOLS && MEMP_USE_CUSTOM_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/priv/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/priv/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 && MEMP_USE_CUSTOM_POOLS */ - -/** Memory pool descriptor */ -struct memp_desc { -#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY - /** Textual description */ - const char *desc; -#endif /* LWIP_DEBUG || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY */ -#if MEMP_STATS - /** Statistics */ - struct stats_mem *stats; -#endif - - /** Element size */ - u16_t size; - -#if !MEMP_MEM_MALLOC - /** Number of elements */ - u16_t num; - - /** Base address */ - u8_t *base; - - /** First free element of each pool. Elements form a linked list. */ - struct memp **tab; -#endif /* MEMP_MEM_MALLOC */ -}; - -#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY -#define DECLARE_LWIP_MEMPOOL_DESC(desc) (desc), -#else -#define DECLARE_LWIP_MEMPOOL_DESC(desc) -#endif - -#if MEMP_STATS -#define LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(name) static struct stats_mem name; -#define LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(name) &name, -#else -#define LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(name) -#define LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(name) -#endif - -void memp_init_pool(const struct memp_desc *desc); - -#if MEMP_OVERFLOW_CHECK -void *memp_malloc_pool_fn(const struct memp_desc* desc, const char* file, const int line); -#define memp_malloc_pool(d) memp_malloc_pool_fn((d), __FILE__, __LINE__) -#else -void *memp_malloc_pool(const struct memp_desc *desc); -#endif -void memp_free_pool(const struct memp_desc* desc, void *mem); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_MEMP_PRIV_H */ diff --git a/core/c/include/lwip/priv/memp_std.h b/core/c/include/lwip/priv/memp_std.h deleted file mode 100755 index 4d3b192..0000000 --- a/core/c/include/lwip/priv/memp_std.h +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @file - * lwIP internal memory pools (do not use in application code) - * This file is deliberately included multiple times: once with empty - * definition of LWIP_MEMPOOL() to handle all includes and multiple times - * to build up various lists of mem pools. - */ - -/* - * 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 + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))), "MALLOC_"#size) -#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) LWIP_MEMPOOL(name, num, (LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) + LWIP_MEM_ALIGN_SIZE(payload)), desc) -#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") -#endif /* LWIP_RAW */ - -#if LWIP_UDP -LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB") -#endif /* LWIP_UDP */ - -#if LWIP_TCP -LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB") -LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN") -LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG") -#endif /* LWIP_TCP */ - -#if LWIP_ALTCP && LWIP_TCP -LWIP_MEMPOOL(ALTCP_PCB, MEMP_NUM_ALTCP_PCB, sizeof(struct altcp_pcb), "ALTCP_PCB") -#endif /* LWIP_ALTCP && LWIP_TCP */ - -#if LWIP_IPV4 && IP_REASSEMBLY -LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA") -#endif /* LWIP_IPV4 && IP_REASSEMBLY */ -#if (IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG) -LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF") -#endif /* IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF || (LWIP_IPV6 && LWIP_IPV6_FRAG) */ - -#if LWIP_NETCONN || LWIP_SOCKET -LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF") -LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN") -#endif /* LWIP_NETCONN || LWIP_SOCKET */ - -#if NO_SYS==0 -LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API") -#if LWIP_MPU_COMPATIBLE -LWIP_MEMPOOL(API_MSG, MEMP_NUM_API_MSG, sizeof(struct api_msg), "API_MSG") -#if LWIP_DNS -LWIP_MEMPOOL(DNS_API_MSG, MEMP_NUM_DNS_API_MSG, sizeof(struct dns_api_msg), "DNS_API_MSG") -#endif -#if LWIP_SOCKET && !LWIP_TCPIP_CORE_LOCKING -LWIP_MEMPOOL(SOCKET_SETGETSOCKOPT_DATA, MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA, sizeof(struct lwip_setgetsockopt_data), "SOCKET_SETGETSOCKOPT_DATA") -#endif -#if LWIP_SOCKET && (LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL) -LWIP_MEMPOOL(SELECT_CB, MEMP_NUM_SELECT_CB, sizeof(struct lwip_select_cb), "SELECT_CB") -#endif /* LWIP_SOCKET && (LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL) */ -#if LWIP_NETIF_API -LWIP_MEMPOOL(NETIFAPI_MSG, MEMP_NUM_NETIFAPI_MSG, sizeof(struct netifapi_msg), "NETIFAPI_MSG") -#endif -#endif /* LWIP_MPU_COMPATIBLE */ -#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 LWIP_IPV4 && LWIP_ARP && ARP_QUEUEING -LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE") -#endif /* LWIP_IPV4 && LWIP_ARP && ARP_QUEUEING */ - -#if LWIP_IGMP -LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP") -#endif /* LWIP_IGMP */ - -#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM -LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT") -#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ - -#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 LWIP_IPV6 && LWIP_ND6_QUEUEING -LWIP_MEMPOOL(ND6_QUEUE, MEMP_NUM_ND6_QUEUE, sizeof(struct nd6_q_entry), "ND6_QUEUE") -#endif /* LWIP_IPV6 && LWIP_ND6_QUEUEING */ - -#if LWIP_IPV6 && LWIP_IPV6_REASS -LWIP_MEMPOOL(IP6_REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip6_reassdata), "IP6_REASSDATA") -#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ - -#if LWIP_IPV6 && LWIP_IPV6_MLD -LWIP_MEMPOOL(MLD6_GROUP, MEMP_NUM_MLD6_GROUP, sizeof(struct mld_group), "MLD6_GROUP") -#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ - - -/* - * 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_MEMPOOL(PBUF, MEMP_NUM_PBUF, sizeof(struct pbuf), "PBUF_REF/ROM") -LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, PBUF_POOL_BUFSIZE, "PBUF_POOL") - - -/* - * 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/core/c/include/lwip/priv/nd6_priv.h b/core/c/include/lwip/priv/nd6_priv.h deleted file mode 100755 index 61c0b73..0000000 --- a/core/c/include/lwip/priv/nd6_priv.h +++ /dev/null @@ -1,142 +0,0 @@ -/** - * @file - * - * Neighbor discovery and stateless address autoconfiguration for IPv6. - * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 - * (Address autoconfiguration). - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#ifndef LWIP_HDR_ND6_PRIV_H -#define LWIP_HDR_ND6_PRIV_H - -#include "lwip/opt.h" - -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/pbuf.h" -#include "lwip/ip6_addr.h" -#include "lwip/netif.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_ND6_QUEUEING -/** struct for queueing outgoing packets for unknown address - * defined here to be accessed by memp.h - */ -struct nd6_q_entry { - struct nd6_q_entry *next; - struct pbuf *p; -}; -#endif /* LWIP_ND6_QUEUEING */ - -/** Struct for tables. */ -struct nd6_neighbor_cache_entry { - ip6_addr_t next_hop_address; - struct netif *netif; - u8_t lladdr[NETIF_MAX_HWADDR_LEN]; - /*u32_t pmtu;*/ -#if LWIP_ND6_QUEUEING - /** Pointer to queue of pending outgoing packets on this entry. */ - struct nd6_q_entry *q; -#else /* LWIP_ND6_QUEUEING */ - /** Pointer to a single pending outgoing packet on this entry. */ - struct pbuf *q; -#endif /* LWIP_ND6_QUEUEING */ - u8_t state; - u8_t isrouter; - union { - u32_t reachable_time; /* in seconds */ - u32_t delay_time; /* ticks (ND6_TMR_INTERVAL) */ - u32_t probes_sent; - u32_t stale_time; /* ticks (ND6_TMR_INTERVAL) */ - } counter; -}; - -struct nd6_destination_cache_entry { - ip6_addr_t destination_addr; - ip6_addr_t next_hop_addr; - u16_t pmtu; - u32_t age; -}; - -struct nd6_prefix_list_entry { - ip6_addr_t prefix; - struct netif *netif; - u32_t invalidation_timer; /* in seconds */ -}; - -struct nd6_router_list_entry { - struct nd6_neighbor_cache_entry *neighbor_entry; - u32_t invalidation_timer; /* in seconds */ - u8_t flags; -}; - -enum nd6_neighbor_cache_entry_state { - ND6_NO_ENTRY = 0, - ND6_INCOMPLETE, - ND6_REACHABLE, - ND6_STALE, - ND6_DELAY, - ND6_PROBE -}; - -#define ND6_HOPLIM 255 /* maximum hop limit, required in all ND packets */ - -#define ND6_2HRS 7200 /* two hours, expressed in number of seconds */ - -/* Router tables. */ -/* @todo make these static? and entries accessible through API? */ -extern struct nd6_neighbor_cache_entry neighbor_cache[]; -extern struct nd6_destination_cache_entry destination_cache[]; -extern struct nd6_prefix_list_entry prefix_list[]; -extern struct nd6_router_list_entry default_router_list[]; - -/* Default values, can be updated by a RA message. */ -extern u32_t reachable_time; -extern u32_t retrans_timer; - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6 */ - -#endif /* LWIP_HDR_ND6_PRIV_H */ diff --git a/core/c/include/lwip/priv/raw_priv.h b/core/c/include/lwip/priv/raw_priv.h deleted file mode 100755 index 0835422..0000000 --- a/core/c/include/lwip/priv/raw_priv.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @file - * raw API internal implementations (do not use in application code) - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef LWIP_HDR_RAW_PRIV_H -#define LWIP_HDR_RAW_PRIV_H - -#include "lwip/opt.h" - -#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/raw.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** return codes for raw_input */ -typedef enum raw_input_state -{ - RAW_INPUT_NONE = 0, /* pbuf did not match any pcbs */ - RAW_INPUT_EATEN, /* pbuf handed off and delivered to pcb */ - RAW_INPUT_DELIVERED /* pbuf only delivered to pcb (pbuf can still be referenced) */ -} raw_input_state_t; - -/* The following functions are the lower layer interface to RAW. */ -raw_input_state_t raw_input(struct pbuf *p, struct netif *inp); - -void raw_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_RAW */ - -#endif /* LWIP_HDR_RAW_PRIV_H */ diff --git a/core/c/include/lwip/priv/sockets_priv.h b/core/c/include/lwip/priv/sockets_priv.h deleted file mode 100755 index e481cd1..0000000 --- a/core/c/include/lwip/priv/sockets_priv.h +++ /dev/null @@ -1,175 +0,0 @@ -/** - * @file - * Sockets API internal implementations (do not use in application code) - */ - -/* - * Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. - * 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: Joel Cunningham - * - */ -#ifndef LWIP_HDR_SOCKETS_PRIV_H -#define LWIP_HDR_SOCKETS_PRIV_H - -#include "lwip/opt.h" - -#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/err.h" -#include "lwip/sockets.h" -#include "lwip/sys.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define NUM_SOCKETS MEMP_NUM_NETCONN - -/** This is overridable for the rare case where more than 255 threads - * select on the same socket... - */ -#ifndef SELWAIT_T -#define SELWAIT_T u8_t -#endif - -union lwip_sock_lastdata { - struct netbuf *netbuf; - struct pbuf *pbuf; -}; - -/** 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 */ - union lwip_sock_lastdata lastdata; -#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL - /** 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; - /** counter of how many threads are waiting for this socket using select */ - SELWAIT_T select_waiting; -#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ -#if LWIP_NETCONN_FULLDUPLEX - /* counter of how many threads are using a struct lwip_sock (not the 'int') */ - u8_t fd_used; - /* status of pending close/delete actions */ - u8_t fd_free_pending; -#define LWIP_SOCK_FD_FREE_TCP 1 -#define LWIP_SOCK_FD_FREE_FREE 2 -#endif -}; - -#ifndef set_errno -#define set_errno(err) do { if (err) { errno = (err); } } while(0) -#endif - -#if !LWIP_TCPIP_CORE_LOCKING -/** Maximum optlen used by setsockopt/getsockopt */ -#define LWIP_SETGETSOCKOPT_MAXOPTLEN LWIP_MAX(16, sizeof(struct ifreq)) - -/** 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 index for which to change options */ - int s; - /** 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 */ -#if LWIP_MPU_COMPATIBLE - u8_t optval[LWIP_SETGETSOCKOPT_MAXOPTLEN]; -#else - union { - void *p; - const void *pc; - } optval; -#endif - /** size of *optval */ - socklen_t optlen; - /** if an error occurs, it is temporarily stored here */ - int err; - /** semaphore to wake up the calling task */ - void* completed_sem; -}; -#endif /* !LWIP_TCPIP_CORE_LOCKING */ - -#ifdef __cplusplus -} -#endif - -struct lwip_sock* lwip_socket_dbg_get_socket(int fd); - -#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL - -#if LWIP_NETCONN_SEM_PER_THREAD -#define SELECT_SEM_T sys_sem_t* -#define SELECT_SEM_PTR(sem) (sem) -#else /* LWIP_NETCONN_SEM_PER_THREAD */ -#define SELECT_SEM_T sys_sem_t -#define SELECT_SEM_PTR(sem) (&(sem)) -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ - -/** 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; -#if LWIP_SOCKET_SELECT - /** readset passed to select */ - fd_set *readset; - /** writeset passed to select */ - fd_set *writeset; - /** unimplemented: exceptset passed to select */ - fd_set *exceptset; -#endif /* LWIP_SOCKET_SELECT */ -#if LWIP_SOCKET_POLL - /** fds passed to poll; NULL if select */ - struct pollfd *poll_fds; - /** nfds passed to poll; 0 if select */ - nfds_t poll_nfds; -#endif /* LWIP_SOCKET_POLL */ - /** don't signal the same semaphore twice: set to 1 when signalled */ - int sem_signalled; - /** semaphore to wake up a task waiting for select */ - SELECT_SEM_T sem; -}; -#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ - -#endif /* LWIP_SOCKET */ - -#endif /* LWIP_HDR_SOCKETS_PRIV_H */ diff --git a/core/c/include/lwip/priv/tcp_priv.h b/core/c/include/lwip/priv/tcp_priv.h deleted file mode 100755 index 96e07e3..0000000 --- a/core/c/include/lwip/priv/tcp_priv.h +++ /dev/null @@ -1,523 +0,0 @@ -/** - * @file - * TCP internal implementations (do not use in application code) - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef LWIP_HDR_TCP_PRIV_H -#define LWIP_HDR_TCP_PRIV_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/mem.h" -#include "lwip/pbuf.h" -#include "lwip/ip.h" -#include "lwip/icmp.h" -#include "lwip/err.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/prot/tcp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Functions for interfacing with TCP: */ - -/* Lower layer interface to TCP: */ -void tcp_init (void); /* Initialize this module. */ -void tcp_tmr (void); /* Must be called every - TCP_TMR_INTERVAL - ms. (Typically 250 ms). */ -/* It is also possible to call these two functions at the right - intervals (instead of calling tcp_tmr()). */ -void tcp_slowtmr (void); -void tcp_fasttmr (void); - -/* Call this from a netif driver (watch out for threading issues!) that has - returned a memory error on transmit and now has free buffers to send more. - This iterates all active pcbs that had an error and tries to call - tcp_output, so use this with care as it might slow down the system. */ -void tcp_txnow (void); - -/* Only used by IP to pass a TCP segment to TCP: */ -void tcp_input (struct pbuf *p, struct netif *inp); -/* Used within the TCP code only: */ -struct tcp_pcb * tcp_alloc (u8_t prio); -void tcp_free (struct tcp_pcb *pcb); -void tcp_abandon (struct tcp_pcb *pcb, int reset); -err_t tcp_send_empty_ack(struct tcp_pcb *pcb); -err_t tcp_rexmit (struct tcp_pcb *pcb); -err_t tcp_rexmit_rto_prepare(struct tcp_pcb *pcb); -void tcp_rexmit_rto_commit(struct tcp_pcb *pcb); -void tcp_rexmit_rto (struct tcp_pcb *pcb); -void tcp_rexmit_fast (struct tcp_pcb *pcb); -u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); -err_t tcp_process_refused_data(struct tcp_pcb *pcb); - -/** - * This is the Nagle algorithm: try to combine user data to send as few TCP - * segments as possible. Only send if - * - no previously transmitted data on the connection remains unacknowledged or - * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or - * - the only unsent segment is at least pcb->mss bytes long (or there is more - * than one unsent segment - with lwIP, this can happen although unsent->len < mss) - * - or if we are in fast-retransmit (TF_INFR) - */ -#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ - ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ - (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ - ((tpcb)->unsent->len >= (tpcb)->mss))) || \ - ((tcp_sndbuf(tpcb) == 0) || (tcp_sndqueuelen(tpcb) >= TCP_SND_QUEUELEN)) \ - ) ? 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)((u32_t)(a) - (u32_t)(b)) < 0) -#define TCP_SEQ_LEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) <= 0) -#define TCP_SEQ_GT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) > 0) -#define TCP_SEQ_GEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(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)) - -#ifndef TCP_TMR_INTERVAL -#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */ -#endif /* TCP_TMR_INTERVAL */ - -#ifndef TCP_FAST_INTERVAL -#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ -#endif /* TCP_FAST_INTERVAL */ - -#ifndef TCP_SLOW_INTERVAL -#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */ -#endif /* TCP_SLOW_INTERVAL */ - -#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ -#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ - -#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ - -#ifndef TCP_MSL -#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ -#endif - -/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ -#ifndef TCP_KEEPIDLE_DEFAULT -#define TCP_KEEPIDLE_DEFAULT 7200000UL /* Default KEEPALIVE timer in milliseconds */ -#endif - -#ifndef TCP_KEEPINTVL_DEFAULT -#define TCP_KEEPINTVL_DEFAULT 75000UL /* Default Time between KEEPALIVE probes in milliseconds */ -#endif - -#ifndef TCP_KEEPCNT_DEFAULT -#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */ -#endif - -#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */ - -#define TCP_TCPLEN(seg) ((seg)->len + (((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0) ? 1U : 0U)) - -/** 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 successfully closed. */ -#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ - - -#if LWIP_EVENT_API - -#define TCP_EVENT_ACCEPT(lpcb,pcb,arg,err,ret) ret = lwip_tcp_event(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) do { if ((pcb)->state != SYN_RCVD) { \ - ret = lwip_tcp_event((pcb)->callback_arg, (pcb), LWIP_EVENT_POLL, NULL, 0, ERR_OK); \ - } else { \ - ret = ERR_ARG; } } while(0) -/* For event API, last state SYN_RCVD must be excluded here: the application - has not seen this pcb, yet! */ -#define TCP_EVENT_ERR(last_state,errf,arg,err) do { if (last_state != SYN_RCVD) { \ - lwip_tcp_event((arg), NULL, LWIP_EVENT_ERR, NULL, 0, (err)); } } while(0) - -#else /* LWIP_EVENT_API */ - -#define TCP_EVENT_ACCEPT(lpcb,pcb,arg,err,ret) \ - do { \ - if((lpcb)->accept != NULL) \ - (ret) = (lpcb)->accept((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(last_state,errf,arg,err) \ - do { \ - LWIP_UNUSED_ARG(last_state); \ - 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 segments on a queue */ - struct pbuf *p; /* buffer containing data + TCP header */ - u16_t len; /* the TCP length of this segment */ -#if TCP_OVERSIZE_DBGCHECK - u16_t oversize_left; /* Extra bytes available at the end of the last - pbuf in unsent (used for asserting vs. - tcp_pcb.unsent_oversize 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 (only used in SYN segments) */ -#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' */ -#define TF_SEG_OPTS_WND_SCALE (u8_t)0x08U /* Include WND SCALE option (only used in SYN segments) */ -#define TF_SEG_OPTS_SACK_PERM (u8_t)0x10U /* Include SACK Permitted option (only used in SYN segments) */ - struct tcp_hdr *tcphdr; /* the TCP header */ -}; - -#define LWIP_TCP_OPT_EOL 0 -#define LWIP_TCP_OPT_NOP 1 -#define LWIP_TCP_OPT_MSS 2 -#define LWIP_TCP_OPT_WS 3 -#define LWIP_TCP_OPT_SACK_PERM 4 -#define LWIP_TCP_OPT_TS 8 - -#define LWIP_TCP_OPT_LEN_MSS 4 -#if LWIP_TCP_TIMESTAMPS -#define LWIP_TCP_OPT_LEN_TS 10 -#define LWIP_TCP_OPT_LEN_TS_OUT 12 /* aligned for output (includes NOP padding) */ -#else -#define LWIP_TCP_OPT_LEN_TS_OUT 0 -#endif -#if LWIP_WND_SCALE -#define LWIP_TCP_OPT_LEN_WS 3 -#define LWIP_TCP_OPT_LEN_WS_OUT 4 /* aligned for output (includes NOP padding) */ -#else -#define LWIP_TCP_OPT_LEN_WS_OUT 0 -#endif - -#if LWIP_TCP_SACK_OUT -#define LWIP_TCP_OPT_LEN_SACK_PERM 2 -#define LWIP_TCP_OPT_LEN_SACK_PERM_OUT 4 /* aligned for output (includes NOP padding) */ -#else -#define LWIP_TCP_OPT_LEN_SACK_PERM_OUT 0 -#endif - -#define LWIP_TCP_OPT_LENGTH(flags) \ - ((flags) & TF_SEG_OPTS_MSS ? LWIP_TCP_OPT_LEN_MSS : 0) + \ - ((flags) & TF_SEG_OPTS_TS ? LWIP_TCP_OPT_LEN_TS_OUT : 0) + \ - ((flags) & TF_SEG_OPTS_WND_SCALE ? LWIP_TCP_OPT_LEN_WS_OUT : 0) + \ - ((flags) & TF_SEG_OPTS_SACK_PERM ? LWIP_TCP_OPT_LEN_SACK_PERM_OUT : 0) - -/** This returns a TCP header option for MSS in an u32_t */ -#define TCP_BUILD_MSS_OPTION(mss) lwip_htonl(0x02040000 | ((mss) & 0xFFFF)) - -#if LWIP_WND_SCALE -#define TCPWNDSIZE_F U32_F -#define TCPWND_MAX 0xFFFFFFFFU -#define TCPWND_CHECK16(x) LWIP_ASSERT("window size > 0xFFFF", (x) <= 0xFFFF) -#define TCPWND_MIN16(x) ((u16_t)LWIP_MIN((x), 0xFFFF)) -#else /* LWIP_WND_SCALE */ -#define TCPWNDSIZE_F U16_F -#define TCPWND_MAX 0xFFFFU -#define TCPWND_CHECK16(x) -#define TCPWND_MIN16(x) x -#endif /* LWIP_WND_SCALE */ - -/* Global variables: */ -extern struct tcp_pcb *tcp_input_pcb; -extern u32_t tcp_ticks; -extern u8_t tcp_active_pcbs_changed; - -/* 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. */ - -#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3 -#define NUM_TCP_PCB_LISTS 4 -extern struct tcp_pcb ** const tcp_pcb_lists[NUM_TCP_PCB_LISTS]; - -/* 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 {\ - struct tcp_pcb *tcp_tmp_pcb; \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %"U16_F"\n", (void *)(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_REG: tcp_pcbs sane", tcp_pcbs_sane()); \ - tcp_timer_needed(); \ - } while(0) -#define TCP_RMV(pcbs, npcb) do { \ - struct tcp_pcb *tcp_tmp_pcb; \ - LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (void *)(npcb), (void *)(*(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", (void *)(npcb), (void *)(*(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 { \ - struct tcp_pcb *tcp_tmp_pcb; \ - 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_REG_ACTIVE(npcb) \ - do { \ - TCP_REG(&tcp_active_pcbs, npcb); \ - tcp_active_pcbs_changed = 1; \ - } while (0) - -#define TCP_RMV_ACTIVE(npcb) \ - do { \ - TCP_RMV(&tcp_active_pcbs, npcb); \ - tcp_active_pcbs_changed = 1; \ - } while (0) - -#define TCP_PCB_REMOVE_ACTIVE(pcb) \ - do { \ - tcp_pcb_remove(&tcp_active_pcbs, pcb); \ - tcp_active_pcbs_changed = 1; \ - } while (0) - - -/* Internal functions: */ -struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb); -void tcp_pcb_purge(struct tcp_pcb *pcb); -void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb); - -void tcp_segs_free(struct tcp_seg *seg); -void tcp_seg_free(struct tcp_seg *seg); -struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg); - -#define tcp_ack(pcb) \ - do { \ - if((pcb)->flags & TF_ACK_DELAY) { \ - tcp_clear_flags(pcb, TF_ACK_DELAY); \ - tcp_ack_now(pcb); \ - } \ - else { \ - tcp_set_flags(pcb, TF_ACK_DELAY); \ - } \ - } while (0) - -#define tcp_ack_now(pcb) \ - tcp_set_flags(pcb, TF_ACK_NOW) - -err_t tcp_send_fin(struct tcp_pcb *pcb); -err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags); - -void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); - -void tcp_rst(const struct tcp_pcb* pcb, u32_t seqno, u32_t ackno, - const ip_addr_t *local_ip, const ip_addr_t *remote_ip, - u16_t local_port, u16_t remote_port); - -u32_t tcp_next_iss(struct tcp_pcb *pcb); - -err_t tcp_keepalive(struct tcp_pcb *pcb); -err_t tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t split); -err_t tcp_zero_window_probe(struct tcp_pcb *pcb); -void tcp_trigger_input_pcb_close(void); - -#if TCP_CALCULATE_EFF_SEND_MSS -u16_t tcp_eff_send_mss_netif(u16_t sendmss, struct netif *outif, - const ip_addr_t *dest); -#define tcp_eff_send_mss(sendmss, src, dest) \ - tcp_eff_send_mss_netif(sendmss, ip_route(src, dest), dest) -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - -#if LWIP_CALLBACK_API -err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); -#endif /* LWIP_CALLBACK_API */ - -#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG -void tcp_debug_print(struct tcp_hdr *tcphdr); -void tcp_debug_print_flags(u8_t flags); -void tcp_debug_print_state(enum tcp_state s); -void tcp_debug_print_pcbs(void); -s16_t tcp_pcbs_sane(void); -#else -# define tcp_debug_print(tcphdr) -# define tcp_debug_print_flags(flags) -# define tcp_debug_print_state(s) -# define tcp_debug_print_pcbs() -# define tcp_pcbs_sane() 1 -#endif /* TCP_DEBUG */ - -/** External function (implemented in timers.c), called when TCP detects - * that a timer is needed (i.e. active- or time-wait-pcb found). */ -void tcp_timer_needed(void); - -void tcp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr); - -#if TCP_QUEUE_OOSEQ -void tcp_free_ooseq(struct tcp_pcb *pcb); -#endif - -#if LWIP_TCP_PCB_NUM_EXT_ARGS -err_t tcp_ext_arg_invoke_callbacks_passive_open(struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_TCP */ - -#endif /* LWIP_HDR_TCP_PRIV_H */ diff --git a/core/c/include/lwip/priv/tcpip_priv.h b/core/c/include/lwip/priv/tcpip_priv.h deleted file mode 100755 index 327673b..0000000 --- a/core/c/include/lwip/priv/tcpip_priv.h +++ /dev/null @@ -1,170 +0,0 @@ -/** - * @file - * TCPIP API internal implementations (do not use in application code) - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef LWIP_HDR_TCPIP_PRIV_H -#define LWIP_HDR_TCPIP_PRIV_H - -#include "lwip/opt.h" - -#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/tcpip.h" -#include "lwip/sys.h" -#include "lwip/timeouts.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct pbuf; -struct netif; - -#if LWIP_MPU_COMPATIBLE -#define API_VAR_REF(name) (*(name)) -#define API_VAR_DECLARE(type, name) type * name -#define API_VAR_ALLOC_EXT(type, pool, name, errorblock) do { \ - name = (type *)memp_malloc(pool); \ - if (name == NULL) { \ - errorblock; \ - } \ - } while(0) -#define API_VAR_ALLOC(type, pool, name, errorval) API_VAR_ALLOC_EXT(type, pool, name, return errorval) -#define API_VAR_ALLOC_POOL(type, pool, name, errorval) do { \ - name = (type *)LWIP_MEMPOOL_ALLOC(pool); \ - if (name == NULL) { \ - return errorval; \ - } \ - } while(0) -#define API_VAR_FREE(pool, name) memp_free(pool, name) -#define API_VAR_FREE_POOL(pool, name) LWIP_MEMPOOL_FREE(pool, name) -#define API_EXPR_REF(expr) (&(expr)) -#if LWIP_NETCONN_SEM_PER_THREAD -#define API_EXPR_REF_SEM(expr) (expr) -#else -#define API_EXPR_REF_SEM(expr) API_EXPR_REF(expr) -#endif -#define API_EXPR_DEREF(expr) expr -#define API_MSG_M_DEF(m) m -#define API_MSG_M_DEF_C(t, m) t m -#else /* LWIP_MPU_COMPATIBLE */ -#define API_VAR_REF(name) name -#define API_VAR_DECLARE(type, name) type name -#define API_VAR_ALLOC_EXT(type, pool, name, errorblock) -#define API_VAR_ALLOC(type, pool, name, errorval) -#define API_VAR_ALLOC_POOL(type, pool, name, errorval) -#define API_VAR_FREE(pool, name) -#define API_VAR_FREE_POOL(pool, name) -#define API_EXPR_REF(expr) expr -#define API_EXPR_REF_SEM(expr) API_EXPR_REF(expr) -#define API_EXPR_DEREF(expr) (*(expr)) -#define API_MSG_M_DEF(m) *m -#define API_MSG_M_DEF_C(t, m) const t * m -#endif /* LWIP_MPU_COMPATIBLE */ - -err_t tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem); - -struct tcpip_api_call_data -{ -#if !LWIP_TCPIP_CORE_LOCKING - err_t err; -#if !LWIP_NETCONN_SEM_PER_THREAD - sys_sem_t sem; -#endif /* LWIP_NETCONN_SEM_PER_THREAD */ -#else /* !LWIP_TCPIP_CORE_LOCKING */ - u8_t dummy; /* avoid empty struct :-( */ -#endif /* !LWIP_TCPIP_CORE_LOCKING */ -}; -typedef err_t (*tcpip_api_call_fn)(struct tcpip_api_call_data* call); -err_t tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call); - -enum tcpip_msg_type { -#if !LWIP_TCPIP_CORE_LOCKING - TCPIP_MSG_API, - TCPIP_MSG_API_CALL, -#endif /* !LWIP_TCPIP_CORE_LOCKING */ -#if !LWIP_TCPIP_CORE_LOCKING_INPUT - TCPIP_MSG_INPKT, -#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ -#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS - TCPIP_MSG_TIMEOUT, - TCPIP_MSG_UNTIMEOUT, -#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ - TCPIP_MSG_CALLBACK, - TCPIP_MSG_CALLBACK_STATIC -}; - -struct tcpip_msg { - enum tcpip_msg_type type; - union { -#if !LWIP_TCPIP_CORE_LOCKING - struct { - tcpip_callback_fn function; - void* msg; - } api_msg; - struct { - tcpip_api_call_fn function; - struct tcpip_api_call_data *arg; - sys_sem_t *sem; - } api_call; -#endif /* LWIP_TCPIP_CORE_LOCKING */ -#if !LWIP_TCPIP_CORE_LOCKING_INPUT - struct { - struct pbuf *p; - struct netif *netif; - netif_input_fn input_fn; - } inp; -#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ - struct { - tcpip_callback_fn function; - void *ctx; - } cb; -#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS - struct { - u32_t msecs; - sys_timeout_handler h; - void *arg; - } tmo; -#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ - } msg; -}; - -#ifdef __cplusplus -} -#endif - -#endif /* !NO_SYS */ - -#endif /* LWIP_HDR_TCPIP_PRIV_H */ diff --git a/core/c/include/lwip/prot/autoip.h b/core/c/include/lwip/prot/autoip.h deleted file mode 100755 index 3fe1532..0000000 --- a/core/c/include/lwip/prot/autoip.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @file - * AutoIP protocol definitions - */ - -/* - * - * 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. - * - */ - -#ifndef LWIP_HDR_PROT_AUTOIP_H -#define LWIP_HDR_PROT_AUTOIP_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* 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) - -/* 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 */ -typedef enum { - AUTOIP_STATE_OFF = 0, - AUTOIP_STATE_PROBING = 1, - AUTOIP_STATE_ANNOUNCING = 2, - AUTOIP_STATE_BOUND = 3 -} autoip_state_enum_t; - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_AUTOIP_H */ diff --git a/core/c/include/lwip/prot/dhcp.h b/core/c/include/lwip/prot/dhcp.h deleted file mode 100755 index 6d16ce3..0000000 --- a/core/c/include/lwip/prot/dhcp.h +++ /dev/null @@ -1,178 +0,0 @@ -/** - * @file - * DHCP protocol definitions - */ - -/* - * 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 part of the lwIP TCP/IP stack. - * - * Author: Leon Woestenberg - * - */ -#ifndef LWIP_HDR_PROT_DHCP_H -#define LWIP_HDR_PROT_DHCP_H - -#include "lwip/opt.h" -#include "lwip/arch.h" -#include "lwip/prot/ip4.h" - -#ifdef __cplusplus -extern "C" { -#endif - - /* DHCP message item offsets and length */ -#define DHCP_CHADDR_LEN 16U -#define DHCP_SNAME_OFS 44U -#define DHCP_SNAME_LEN 64U -#define DHCP_FILE_OFS 108U -#define DHCP_FILE_LEN 128U -#define DHCP_MSG_LEN 236U -#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4U) /* 4 byte: cookie */ - -#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_FLD_8(u8_t op); - PACK_STRUCT_FLD_8(u8_t htype); - PACK_STRUCT_FLD_8(u8_t hlen); - PACK_STRUCT_FLD_8(u8_t hops); - PACK_STRUCT_FIELD(u32_t xid); - PACK_STRUCT_FIELD(u16_t secs); - PACK_STRUCT_FIELD(u16_t flags); - PACK_STRUCT_FLD_S(ip4_addr_p_t ciaddr); - PACK_STRUCT_FLD_S(ip4_addr_p_t yiaddr); - PACK_STRUCT_FLD_S(ip4_addr_p_t siaddr); - PACK_STRUCT_FLD_S(ip4_addr_p_t giaddr); - PACK_STRUCT_FLD_8(u8_t chaddr[DHCP_CHADDR_LEN]); - PACK_STRUCT_FLD_8(u8_t sname[DHCP_SNAME_LEN]); - PACK_STRUCT_FLD_8(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_FLD_8(u8_t options[DHCP_OPTIONS_LEN]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - - -/* DHCP client states */ -typedef enum { - DHCP_STATE_OFF = 0, - DHCP_STATE_REQUESTING = 1, - DHCP_STATE_INIT = 2, - DHCP_STATE_REBOOTING = 3, - DHCP_STATE_REBINDING = 4, - DHCP_STATE_RENEWING = 5, - DHCP_STATE_SELECTING = 6, - DHCP_STATE_INFORMING = 7, - DHCP_STATE_CHECKING = 8, - DHCP_STATE_PERMANENT = 9, /* not yet implemented */ - DHCP_STATE_BOUND = 10, - DHCP_STATE_RELEASING = 11, /* not yet implemented */ - DHCP_STATE_BACKING_OFF = 12 -} dhcp_state_enum_t; - -/* DHCP op codes */ -#define DHCP_BOOTREQUEST 1 -#define DHCP_BOOTREPLY 2 - -/* DHCP message types */ -#define DHCP_DISCOVER 1 -#define DHCP_OFFER 2 -#define DHCP_REQUEST 3 -#define DHCP_DECLINE 4 -#define DHCP_ACK 5 -#define DHCP_NAK 6 -#define DHCP_RELEASE 7 -#define DHCP_INFORM 8 - -#define DHCP_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_NTP 42 -#define DHCP_OPTION_END 255 - -/* 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_HDR_PROT_DHCP_H */ diff --git a/core/c/include/lwip/prot/dhcp6.h b/core/c/include/lwip/prot/dhcp6.h deleted file mode 100755 index 1be5f84..0000000 --- a/core/c/include/lwip/prot/dhcp6.h +++ /dev/null @@ -1,138 +0,0 @@ -/** - * @file - * DHCPv6 protocol definitions - */ - -/* - * Copyright (c) 2017 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ -#ifndef LWIP_HDR_PROT_DHCP6_H -#define LWIP_HDR_PROT_DHCP6_H - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define DHCP6_CLIENT_PORT 546 -#define DHCP6_SERVER_PORT 547 - - - /* DHCPv6 message item offsets and length */ -#define DHCP6_TRANSACTION_ID_LEN 3 - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** minimum set of fields of any DHCPv6 message */ -struct dhcp6_msg -{ - PACK_STRUCT_FLD_8(u8_t msgtype); - PACK_STRUCT_FLD_8(u8_t transaction_id[DHCP6_TRANSACTION_ID_LEN]); - /* options follow */ -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - - -/* DHCP6 client states */ -typedef enum { - DHCP6_STATE_OFF = 0, - DHCP6_STATE_STATELESS_IDLE = 1, - DHCP6_STATE_REQUESTING_CONFIG = 2 -} dhcp6_state_enum_t; - -/* DHCPv6 message types */ -#define DHCP6_SOLICIT 1 -#define DHCP6_ADVERTISE 2 -#define DHCP6_REQUEST 3 -#define DHCP6_CONFIRM 4 -#define DHCP6_RENEW 5 -#define DHCP6_REBIND 6 -#define DHCP6_REPLY 7 -#define DHCP6_RELEASE 8 -#define DHCP6_DECLINE 9 -#define DHCP6_RECONFIGURE 10 -#define DHCP6_INFOREQUEST 11 -#define DHCP6_RELAYFORW 12 -#define DHCP6_RELAYREPL 13 -/* More message types see https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml */ - -/** DHCPv6 status codes */ -#define DHCP6_STATUS_SUCCESS 0 /* Success. */ -#define DHCP6_STATUS_UNSPECFAIL 1 /* Failure, reason unspecified; this status code is sent by either a client or a server to indicate a failure not explicitly specified in this document. */ -#define DHCP6_STATUS_NOADDRSAVAIL 2 /* Server has no addresses available to assign to the IA(s). */ -#define DHCP6_STATUS_NOBINDING 3 /* Client record (binding) unavailable. */ -#define DHCP6_STATUS_NOTONLINK 4 /* The prefix for the address is not appropriate for the link to which the client is attached. */ -#define DHCP6_STATUS_USEMULTICAST 5 /* Sent by a server to a client to force the client to send messages to the server using the All_DHCP_Relay_Agents_and_Servers address. */ -/* More status codes see https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml */ - -/** DHCPv6 DUID types */ -#define DHCP6_DUID_LLT 1 /* LLT: Link-layer Address Plus Time */ -#define DHCP6_DUID_EN 2 /* EN: Enterprise number */ -#define DHCP6_DUID_LL 3 /* LL: Link-layer Address */ -#define DHCP6_DUID_UUID 4 /* UUID (RFC 6355) */ - -/* DHCPv6 options */ -#define DHCP6_OPTION_CLIENTID 1 -#define DHCP6_OPTION_SERVERID 2 -#define DHCP6_OPTION_IA_NA 3 -#define DHCP6_OPTION_IA_TA 4 -#define DHCP6_OPTION_IAADDR 5 -#define DHCP6_OPTION_ORO 6 -#define DHCP6_OPTION_PREFERENCE 7 -#define DHCP6_OPTION_ELAPSED_TIME 8 -#define DHCP6_OPTION_RELAY_MSG 9 -#define DHCP6_OPTION_AUTH 11 -#define DHCP6_OPTION_UNICAST 12 -#define DHCP6_OPTION_STATUS_CODE 13 -#define DHCP6_OPTION_RAPID_COMMIT 14 -#define DHCP6_OPTION_USER_CLASS 15 -#define DHCP6_OPTION_VENDOR_CLASS 16 -#define DHCP6_OPTION_VENDOR_OPTS 17 -#define DHCP6_OPTION_INTERFACE_ID 18 -#define DHCP6_OPTION_RECONF_MSG 19 -#define DHCP6_OPTION_RECONF_ACCEPT 20 -/* More options see https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml */ -#define DHCP6_OPTION_DNS_SERVERS 23 /* RFC 3646 */ -#define DHCP6_OPTION_DOMAIN_LIST 24 /* RFC 3646 */ -#define DHCP6_OPTION_SNTP_SERVERS 31 /* RFC 4075 */ - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_DHCP6_H */ diff --git a/core/c/include/lwip/prot/dns.h b/core/c/include/lwip/prot/dns.h deleted file mode 100755 index 022a32c..0000000 --- a/core/c/include/lwip/prot/dns.h +++ /dev/null @@ -1,140 +0,0 @@ -/** - * @file - * DNS - host name to IP address resolver. - */ - -/* - * Port to lwIP from uIP - * by Jim Pettinato April 2007 - * - * security fixes and more by Simon Goldschmidt - * - * 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. - */ - -#ifndef LWIP_HDR_PROT_DNS_H -#define LWIP_HDR_PROT_DNS_H - -#include "lwip/arch.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** DNS server port address */ -#ifndef DNS_SERVER_PORT -#define DNS_SERVER_PORT 53 -#endif - -/* 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_AAAA 28 /* IPv6 address */ -#define DNS_RRTYPE_SRV 33 /* service location */ -#define DNS_RRTYPE_ANY 255 /* any type */ - -/* 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_ANY 255 /* any class */ -#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ - -/* 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 - -#define DNS_HDR_GET_OPCODE(hdr) ((((hdr)->flags1) >> 3) & 0xF) - -#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_FLD_8(u8_t flags1); - PACK_STRUCT_FLD_8(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 - - -/* Multicast DNS definitions */ - -/** UDP port for multicast DNS queries */ -#ifndef DNS_MQUERY_PORT -#define DNS_MQUERY_PORT 5353 -#endif - -/* IPv4 group for multicast DNS queries: 224.0.0.251 */ -#ifndef DNS_MQUERY_IPV4_GROUP_INIT -#define DNS_MQUERY_IPV4_GROUP_INIT IPADDR4_INIT_BYTES(224,0,0,251) -#endif - -/* IPv6 group for multicast DNS queries: FF02::FB */ -#ifndef DNS_MQUERY_IPV6_GROUP_INIT -#define DNS_MQUERY_IPV6_GROUP_INIT IPADDR6_INIT_HOST(0xFF020000,0,0,0xFB) -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_DNS_H */ diff --git a/core/c/include/lwip/prot/etharp.h b/core/c/include/lwip/prot/etharp.h deleted file mode 100755 index 9e4b02c..0000000 --- a/core/c/include/lwip/prot/etharp.h +++ /dev/null @@ -1,114 +0,0 @@ -/** - * @file - * ARP protocol definitions - */ - -/* - * 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_HDR_PROT_ETHARP_H -#define LWIP_HDR_PROT_ETHARP_H - -#include "lwip/arch.h" -#include "lwip/prot/ethernet.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef ETHARP_HWADDR_LEN -#define ETHARP_HWADDR_LEN ETH_HWADDR_LEN -#endif - -/** - * struct ip4_addr_wordaligned 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 ip4_addr_wordaligned { - PACK_STRUCT_FIELD(u16_t addrw[2]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#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 IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T -#define IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(dest, src) SMEMCPY(dest, src, sizeof(ip4_addr_t)) -#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 IPADDR_WORDALIGNED_COPY_FROM_IP4_ADDR_T -#define IPADDR_WORDALIGNED_COPY_FROM_IP4_ADDR_T(dest, src) SMEMCPY(dest, src, sizeof(ip4_addr_t)) -#endif - -#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_FLD_8(u8_t hwlen); - PACK_STRUCT_FLD_8(u8_t protolen); - PACK_STRUCT_FIELD(u16_t opcode); - PACK_STRUCT_FLD_S(struct eth_addr shwaddr); - PACK_STRUCT_FLD_S(struct ip4_addr_wordaligned sipaddr); - PACK_STRUCT_FLD_S(struct eth_addr dhwaddr); - PACK_STRUCT_FLD_S(struct ip4_addr_wordaligned dipaddr); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define SIZEOF_ETHARP_HDR 28 - -/* ARP message types (opcodes) */ -enum etharp_opcode { - ARP_REQUEST = 1, - ARP_REPLY = 2 -}; - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_ETHARP_H */ diff --git a/core/c/include/lwip/prot/ethernet.h b/core/c/include/lwip/prot/ethernet.h deleted file mode 100755 index fef49e2..0000000 --- a/core/c/include/lwip/prot/ethernet.h +++ /dev/null @@ -1,125 +0,0 @@ -/** - * @file - * Ethernet protocol definitions - */ - -/* - * 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_HDR_PROT_ETHERNET_H -#define LWIP_HDR_PROT_ETHERNET_H - -#include "lwip/arch.h" -#include "lwip/prot/ieee.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef ETH_HWADDR_LEN -#ifdef ETHARP_HWADDR_LEN -#define ETH_HWADDR_LEN ETHARP_HWADDR_LEN /* compatibility mode */ -#else -#define ETH_HWADDR_LEN 6 -#endif -#endif - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** An Ethernet MAC address */ -struct eth_addr { - PACK_STRUCT_FLD_8(u8_t addr[ETH_HWADDR_LEN]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** Initialize a struct eth_addr with its 6 bytes (takes care of correct braces) */ -#define ETH_ADDR(b0, b1, b2, b3, b4, b5) {{b0, b1, b2, b3, b4, b5}} - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** Ethernet header */ -struct eth_hdr { -#if ETH_PAD_SIZE - PACK_STRUCT_FLD_8(u8_t padding[ETH_PAD_SIZE]); -#endif - PACK_STRUCT_FLD_S(struct eth_addr dest); - PACK_STRUCT_FLD_S(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) - -#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 prio_vid); - PACK_STRUCT_FIELD(u16_t tpid); -} 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) (lwip_htons((vlan_hdr)->prio_vid) & 0xFFF) - -/** The 24-bit IANA IPv4-multicast OUI is 01-00-5e: */ -#define LL_IP4_MULTICAST_ADDR_0 0x01 -#define LL_IP4_MULTICAST_ADDR_1 0x00 -#define LL_IP4_MULTICAST_ADDR_2 0x5e - -/** IPv6 multicast uses this prefix */ -#define LL_IP6_MULTICAST_ADDR_0 0x33 -#define LL_IP6_MULTICAST_ADDR_1 0x33 - -#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETH_HWADDR_LEN) == 0) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_ETHERNET_H */ diff --git a/core/c/include/lwip/prot/iana.h b/core/c/include/lwip/prot/iana.h deleted file mode 100755 index 859d238..0000000 --- a/core/c/include/lwip/prot/iana.h +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @file - * IANA assigned numbers (RFC 1700 and successors) - * - * @defgroup iana IANA assigned numbers - * @ingroup infrastructure - */ - -/* - * Copyright (c) 2017 Dirk Ziegelmeier. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Dirk Ziegelmeier - * - */ - -#ifndef LWIP_HDR_PROT_IANA_H -#define LWIP_HDR_PROT_IANA_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @ingroup iana - * Hardware types - */ -enum lwip_iana_hwtype { - /** Ethernet */ - LWIP_IANA_HWTYPE_ETHERNET = 1 -}; - -/** - * @ingroup iana - * Port numbers - * https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt - */ -enum lwip_iana_port_number { - /** SMTP */ - LWIP_IANA_PORT_SMTP = 25, - /** DHCP server */ - LWIP_IANA_PORT_DHCP_SERVER = 67, - /** DHCP client */ - LWIP_IANA_PORT_DHCP_CLIENT = 68, - /** TFTP */ - LWIP_IANA_PORT_TFTP = 69, - /** HTTP */ - LWIP_IANA_PORT_HTTP = 80, - /** SNTP */ - LWIP_IANA_PORT_SNTP = 123, - /** NETBIOS */ - LWIP_IANA_PORT_NETBIOS = 137, - /** SNMP */ - LWIP_IANA_PORT_SNMP = 161, - /** SNMP traps */ - LWIP_IANA_PORT_SNMP_TRAP = 162, - /** HTTPS */ - LWIP_IANA_PORT_HTTPS = 443, - /** SMTPS */ - LWIP_IANA_PORT_SMTPS = 465, - /** MQTT */ - LWIP_IANA_PORT_MQTT = 1883, - /** MDNS */ - LWIP_IANA_PORT_MDNS = 5353, - /** Secure MQTT */ - LWIP_IANA_PORT_SECURE_MQTT = 8883 -}; - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_IANA_H */ diff --git a/core/c/include/lwip/prot/icmp.h b/core/c/include/lwip/prot/icmp.h deleted file mode 100755 index d8183fd..0000000 --- a/core/c/include/lwip/prot/icmp.h +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @file - * ICMP protocol definitions - */ - -/* - * 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_HDR_PROT_ICMP_H -#define LWIP_HDR_PROT_ICMP_H - -#include "lwip/arch.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 */ -#define ICMP_AM 17 /* address mask request */ -#define ICMP_AMR 18 /* address mask reply */ - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -/** This is the standard ICMP header only that the u32_t data - * is split to two u16_t like ICMP echo needs it. - * This header is also used for other ICMP types that do not - * use the data part. - */ -PACK_STRUCT_BEGIN -struct icmp_echo_hdr { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(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 - -/* Compatibility defines, old versions used to combine type and code to an u16_t */ -#define ICMPH_TYPE(hdr) ((hdr)->type) -#define ICMPH_CODE(hdr) ((hdr)->code) -#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) -#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_ICMP_H */ diff --git a/core/c/include/lwip/prot/icmp6.h b/core/c/include/lwip/prot/icmp6.h deleted file mode 100755 index b1c6d56..0000000 --- a/core/c/include/lwip/prot/icmp6.h +++ /dev/null @@ -1,170 +0,0 @@ -/** - * @file - * ICMP6 protocol definitions - */ - -/* - * 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_HDR_PROT_ICMP6_H -#define LWIP_HDR_PROT_ICMP6_H - -#include "lwip/arch.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** ICMP type */ -enum icmp6_type { - /** Destination unreachable */ - ICMP6_TYPE_DUR = 1, - /** Packet too big */ - ICMP6_TYPE_PTB = 2, - /** Time exceeded */ - ICMP6_TYPE_TE = 3, - /** Parameter problem */ - ICMP6_TYPE_PP = 4, - /** Private experimentation */ - ICMP6_TYPE_PE1 = 100, - /** Private experimentation */ - ICMP6_TYPE_PE2 = 101, - /** Reserved for expansion of error messages */ - ICMP6_TYPE_RSV_ERR = 127, - - /** Echo request */ - ICMP6_TYPE_EREQ = 128, - /** Echo reply */ - ICMP6_TYPE_EREP = 129, - /** Multicast listener query */ - ICMP6_TYPE_MLQ = 130, - /** Multicast listener report */ - ICMP6_TYPE_MLR = 131, - /** Multicast listener done */ - ICMP6_TYPE_MLD = 132, - /** Router solicitation */ - ICMP6_TYPE_RS = 133, - /** Router advertisement */ - ICMP6_TYPE_RA = 134, - /** Neighbor solicitation */ - ICMP6_TYPE_NS = 135, - /** Neighbor advertisement */ - ICMP6_TYPE_NA = 136, - /** Redirect */ - ICMP6_TYPE_RD = 137, - /** Multicast router advertisement */ - ICMP6_TYPE_MRA = 151, - /** Multicast router solicitation */ - ICMP6_TYPE_MRS = 152, - /** Multicast router termination */ - ICMP6_TYPE_MRT = 153, - /** Private experimentation */ - ICMP6_TYPE_PE3 = 200, - /** Private experimentation */ - ICMP6_TYPE_PE4 = 201, - /** Reserved for expansion of informational messages */ - ICMP6_TYPE_RSV_INF = 255 -}; - -/** ICMP destination unreachable codes */ -enum icmp6_dur_code { - /** No route to destination */ - ICMP6_DUR_NO_ROUTE = 0, - /** Communication with destination administratively prohibited */ - ICMP6_DUR_PROHIBITED = 1, - /** Beyond scope of source address */ - ICMP6_DUR_SCOPE = 2, - /** Address unreachable */ - ICMP6_DUR_ADDRESS = 3, - /** Port unreachable */ - ICMP6_DUR_PORT = 4, - /** Source address failed ingress/egress policy */ - ICMP6_DUR_POLICY = 5, - /** Reject route to destination */ - ICMP6_DUR_REJECT_ROUTE = 6 -}; - -/** ICMP time exceeded codes */ -enum icmp6_te_code { - /** Hop limit exceeded in transit */ - ICMP6_TE_HL = 0, - /** Fragment reassembly time exceeded */ - ICMP6_TE_FRAG = 1 -}; - -/** ICMP parameter code */ -enum icmp6_pp_code { - /** Erroneous header field encountered */ - ICMP6_PP_FIELD = 0, - /** Unrecognized next header type encountered */ - ICMP6_PP_HEADER = 1, - /** Unrecognized IPv6 option encountered */ - ICMP6_PP_OPTION = 2 -}; - -/** This is the standard ICMP6 header. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct icmp6_hdr { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t code); - PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FIELD(u32_t data); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** This is the ICMP6 header adapted for echo req/resp. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct icmp6_echo_hdr { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(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 - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_ICMP6_H */ diff --git a/core/c/include/lwip/prot/ieee.h b/core/c/include/lwip/prot/ieee.h deleted file mode 100755 index ef651b1..0000000 --- a/core/c/include/lwip/prot/ieee.h +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @file - * IEEE assigned numbers - * - * @defgroup ieee IEEE assigned numbers - * @ingroup infrastructure - */ - -/* - * Copyright (c) 2017 Dirk Ziegelmeier. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Dirk Ziegelmeier - * - */ - -#ifndef LWIP_HDR_PROT_IEEE_H -#define LWIP_HDR_PROT_IEEE_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @ingroup ieee - * A list of often ethtypes (although lwIP does not use all of them). - */ -enum lwip_ieee_eth_type { - /** Internet protocol v4 */ - ETHTYPE_IP = 0x0800U, - /** Address resolution protocol */ - ETHTYPE_ARP = 0x0806U, - /** Wake on lan */ - ETHTYPE_WOL = 0x0842U, - /** RARP */ - ETHTYPE_RARP = 0x8035U, - /** Virtual local area network */ - ETHTYPE_VLAN = 0x8100U, - /** Internet protocol v6 */ - ETHTYPE_IPV6 = 0x86DDU, - /** PPP Over Ethernet Discovery Stage */ - ETHTYPE_PPPOEDISC = 0x8863U, - /** PPP Over Ethernet Session Stage */ - ETHTYPE_PPPOE = 0x8864U, - /** Jumbo Frames */ - ETHTYPE_JUMBO = 0x8870U, - /** Process field network */ - ETHTYPE_PROFINET = 0x8892U, - /** Ethernet for control automation technology */ - ETHTYPE_ETHERCAT = 0x88A4U, - /** Link layer discovery protocol */ - ETHTYPE_LLDP = 0x88CCU, - /** Serial real-time communication system */ - ETHTYPE_SERCOS = 0x88CDU, - /** Media redundancy protocol */ - ETHTYPE_MRP = 0x88E3U, - /** Precision time protocol */ - ETHTYPE_PTP = 0x88F7U, - /** Q-in-Q, 802.1ad */ - ETHTYPE_QINQ = 0x9100U -}; - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_IEEE_H */ diff --git a/core/c/include/lwip/prot/igmp.h b/core/c/include/lwip/prot/igmp.h deleted file mode 100755 index 41e4e67..0000000 --- a/core/c/include/lwip/prot/igmp.h +++ /dev/null @@ -1,90 +0,0 @@ -/** - * @file - * IGMP protocol definitions - */ - -/* - * 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_HDR_PROT_IGMP_H -#define LWIP_HDR_PROT_IGMP_H - -#include "lwip/arch.h" -#include "lwip/prot/ip4.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * IGMP constants - */ -#define IGMP_TTL 1 -#define IGMP_MINLEN 8 -#define ROUTER_ALERT 0x9404U -#define ROUTER_ALERTLEN 4 - -/* - * IGMP message types, including version number. - */ -#define IGMP_MEMB_QUERY 0x11 /* Membership query */ -#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */ -#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */ -#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ - -/* Group membership states */ -#define IGMP_GROUP_NON_MEMBER 0 -#define IGMP_GROUP_DELAYING_MEMBER 1 -#define IGMP_GROUP_IDLE_MEMBER 2 - -/** - * IGMP packet format. - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct igmp_msg { - PACK_STRUCT_FLD_8(u8_t igmp_msgtype); - PACK_STRUCT_FLD_8(u8_t igmp_maxresp); - PACK_STRUCT_FIELD(u16_t igmp_checksum); - PACK_STRUCT_FLD_S(ip4_addr_p_t igmp_group_address); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_IGMP_H */ diff --git a/core/c/include/lwip/prot/ip.h b/core/c/include/lwip/prot/ip.h deleted file mode 100755 index 3ce496c..0000000 --- a/core/c/include/lwip/prot/ip.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @file - * IP protocol definitions - */ - -/* - * 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_HDR_PROT_IP_H -#define LWIP_HDR_PROT_IP_H - -#include "lwip/arch.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#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 operates on a void* by loading the first byte */ -#define IP_HDR_GET_VERSION(ptr) ((*(u8_t*)(ptr)) >> 4) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_IP_H */ diff --git a/core/c/include/lwip/prot/ip4.h b/core/c/include/lwip/prot/ip4.h deleted file mode 100755 index 4635a7a..0000000 --- a/core/c/include/lwip/prot/ip4.h +++ /dev/null @@ -1,131 +0,0 @@ -/** - * @file - * IPv4 protocol definitions - */ - -/* - * 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_HDR_PROT_IP4_H -#define LWIP_HDR_PROT_IP4_H - -#include "lwip/arch.h" -#include "lwip/ip4_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** This is the packed version of ip4_addr_t, - used in network headers that are itself packed */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip4_addr_packed { - PACK_STRUCT_FIELD(u32_t addr); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -typedef struct ip4_addr_packed ip4_addr_p_t; - -/* Size of the IPv4 header. Same as 'sizeof(struct ip_hdr)'. */ -#define IP_HLEN 20 -/* Maximum size of the IPv4 header with options. */ -#define IP_HLEN_MAX 60 - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/* The IPv4 header */ -struct ip_hdr { - /* version / header length */ - PACK_STRUCT_FLD_8(u8_t _v_hl); - /* type of service */ - PACK_STRUCT_FLD_8(u8_t _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 0x8000U /* reserved fragment flag */ -#define IP_DF 0x4000U /* don't fragment flag */ -#define IP_MF 0x2000U /* more fragments flag */ -#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */ - /* time to live */ - PACK_STRUCT_FLD_8(u8_t _ttl); - /* protocol*/ - PACK_STRUCT_FLD_8(u8_t _proto); - /* checksum */ - PACK_STRUCT_FIELD(u16_t _chksum); - /* source and destination IP addresses */ - PACK_STRUCT_FLD_S(ip4_addr_p_t src); - PACK_STRUCT_FLD_S(ip4_addr_p_t dest); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/* Macros to get struct ip_hdr fields: */ -#define IPH_V(hdr) ((hdr)->_v_hl >> 4) -#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f) -#define IPH_HL_BYTES(hdr) ((u8_t)(IPH_HL(hdr) * 4)) -#define IPH_TOS(hdr) ((hdr)->_tos) -#define IPH_LEN(hdr) ((hdr)->_len) -#define IPH_ID(hdr) ((hdr)->_id) -#define IPH_OFFSET(hdr) ((hdr)->_offset) -#define IPH_OFFSET_BYTES(hdr) ((u16_t)((lwip_ntohs(IPH_OFFSET(hdr)) & IP_OFFMASK) * 8U)) -#define IPH_TTL(hdr) ((hdr)->_ttl) -#define IPH_PROTO(hdr) ((hdr)->_proto) -#define IPH_CHKSUM(hdr) ((hdr)->_chksum) - -/* Macros to set struct ip_hdr fields: */ -#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (u8_t)((((v) << 4) | (hl))) -#define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (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) - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_IP4_H */ diff --git a/core/c/include/lwip/prot/ip6.h b/core/c/include/lwip/prot/ip6.h deleted file mode 100755 index 272d6ce..0000000 --- a/core/c/include/lwip/prot/ip6.h +++ /dev/null @@ -1,233 +0,0 @@ -/** - * @file - * IPv6 protocol definitions - */ - -/* - * 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_HDR_PROT_IP6_H -#define LWIP_HDR_PROT_IP6_H - -#include "lwip/arch.h" -#include "lwip/ip6_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** This is the packed version of ip6_addr_t, - used in network headers that are itself packed */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip6_addr_packed { - PACK_STRUCT_FIELD(u32_t addr[4]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -typedef struct ip6_addr_packed ip6_addr_p_t; - -#define IP6_HLEN 40 - -#define IP6_NEXTH_HOPBYHOP 0 -#define IP6_NEXTH_TCP 6 -#define IP6_NEXTH_UDP 17 -#define IP6_NEXTH_ENCAPS 41 -#define IP6_NEXTH_ROUTING 43 -#define IP6_NEXTH_FRAGMENT 44 -#define IP6_NEXTH_ICMP6 58 -#define IP6_NEXTH_NONE 59 -#define IP6_NEXTH_DESTOPTS 60 -#define IP6_NEXTH_UDPLITE 136 - -/** The IPv6 header. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip6_hdr { - /** version / traffic class / flow label */ - PACK_STRUCT_FIELD(u32_t _v_tc_fl); - /** payload length */ - PACK_STRUCT_FIELD(u16_t _plen); - /** next header */ - PACK_STRUCT_FLD_8(u8_t _nexth); - /** hop limit */ - PACK_STRUCT_FLD_8(u8_t _hoplim); - /** source and destination IP addresses */ - PACK_STRUCT_FLD_S(ip6_addr_p_t src); - PACK_STRUCT_FLD_S(ip6_addr_p_t dest); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -#define IP6H_V(hdr) ((lwip_ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f) -#define IP6H_TC(hdr) ((lwip_ntohl((hdr)->_v_tc_fl) >> 20) & 0xff) -#define IP6H_FL(hdr) (lwip_ntohl((hdr)->_v_tc_fl) & 0x000fffff) -#define IP6H_PLEN(hdr) (lwip_ntohs((hdr)->_plen)) -#define IP6H_NEXTH(hdr) ((hdr)->_nexth) -#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6) -#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim) -#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (lwip_htonl((((u32_t)(v)) << 28) | (((u32_t)(tc)) << 20) | (fl))) -#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = lwip_htons(plen) -#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth) -#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl) - -/* ipv6 extended options header */ -#define IP6_PAD1_OPTION 0 -#define IP6_PADN_OPTION 1 -#define IP6_ROUTER_ALERT_OPTION 5 -#define IP6_JUMBO_OPTION 194 -#define IP6_HOME_ADDRESS_OPTION 201 -#define IP6_ROUTER_ALERT_DLEN 2 -#define IP6_ROUTER_ALERT_VALUE_MLD 0 - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip6_opt_hdr { - /* router alert option type */ - PACK_STRUCT_FLD_8(u8_t _opt_type); - /* router alert option data len */ - PACK_STRUCT_FLD_8(u8_t _opt_dlen); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -#define IP6_OPT_HLEN 2 -#define IP6_OPT_TYPE_ACTION(hdr) ((((hdr)->_opt_type) >> 6) & 0x3) -#define IP6_OPT_TYPE_CHANGE(hdr) ((((hdr)->_opt_type) >> 5) & 0x1) -#define IP6_OPT_TYPE(hdr) ((hdr)->_opt_type) -#define IP6_OPT_DLEN(hdr) ((hdr)->_opt_dlen) - -/* Hop-by-Hop header. */ -#define IP6_HBH_HLEN 2 - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip6_hbh_hdr { - /* next header */ - PACK_STRUCT_FLD_8(u8_t _nexth); - /* header length in 8-octet units */ - PACK_STRUCT_FLD_8(u8_t _hlen); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -#define IP6_HBH_NEXTH(hdr) ((hdr)->_nexth) - -/* Destination header. */ -#define IP6_DEST_HLEN 2 - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip6_dest_hdr { - /* next header */ - PACK_STRUCT_FLD_8(u8_t _nexth); - /* header length in 8-octet units */ - PACK_STRUCT_FLD_8(u8_t _hlen); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -#define IP6_DEST_NEXTH(hdr) ((hdr)->_nexth) - -/* Routing header */ -#define IP6_ROUT_TYPE2 2 -#define IP6_ROUT_RPL 3 - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip6_rout_hdr { - /* next header */ - PACK_STRUCT_FLD_8(u8_t _nexth); - /* reserved */ - PACK_STRUCT_FLD_8(u8_t _hlen); - /* fragment offset */ - PACK_STRUCT_FIELD(u8_t _routing_type); - /* fragmented packet identification */ - PACK_STRUCT_FIELD(u8_t _segments_left); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -#define IP6_ROUT_NEXTH(hdr) ((hdr)->_nexth) -#define IP6_ROUT_TYPE(hdr) ((hdr)->_routing_type) -#define IP6_ROUT_SEG_LEFT(hdr) ((hdr)->_segments_left) - -/* Fragment header. */ -#define IP6_FRAG_HLEN 8 -#define IP6_FRAG_OFFSET_MASK 0xfff8 -#define IP6_FRAG_MORE_FLAG 0x0001 - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip6_frag_hdr { - /* next header */ - PACK_STRUCT_FLD_8(u8_t _nexth); - /* reserved */ - PACK_STRUCT_FLD_8(u8_t reserved); - /* fragment offset */ - PACK_STRUCT_FIELD(u16_t _fragment_offset); - /* fragmented packet identification */ - PACK_STRUCT_FIELD(u32_t _identification); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -#define IP6_FRAG_NEXTH(hdr) ((hdr)->_nexth) -#define IP6_FRAG_MBIT(hdr) (lwip_ntohs((hdr)->_fragment_offset) & 0x1) -#define IP6_FRAG_ID(hdr) (lwip_ntohl((hdr)->_identification)) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_IP6_H */ diff --git a/core/c/include/lwip/prot/mld6.h b/core/c/include/lwip/prot/mld6.h deleted file mode 100755 index 27a63bf..0000000 --- a/core/c/include/lwip/prot/mld6.h +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @file - * MLD6 protocol definitions - */ - -/* - * 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_HDR_PROT_MLD6_H -#define LWIP_HDR_PROT_MLD6_H - -#include "lwip/arch.h" -#include "lwip/prot/ip6.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define MLD6_HBH_HLEN 8 -/** Multicast listener report/query/done message header. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct mld_header { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t code); - PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FIELD(u16_t max_resp_delay); - PACK_STRUCT_FIELD(u16_t reserved); - PACK_STRUCT_FLD_S(ip6_addr_p_t multicast_address); - /* Options follow. */ -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_MLD6_H */ diff --git a/core/c/include/lwip/prot/nd6.h b/core/c/include/lwip/prot/nd6.h deleted file mode 100755 index af87e29..0000000 --- a/core/c/include/lwip/prot/nd6.h +++ /dev/null @@ -1,274 +0,0 @@ -/** - * @file - * ND6 protocol definitions - */ - -/* - * 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_HDR_PROT_ND6_H -#define LWIP_HDR_PROT_ND6_H - -#include "lwip/arch.h" -#include "lwip/ip6_addr.h" -#include "lwip/prot/ip6.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Neighbor solicitation message header. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ns_header { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t code); - PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FIELD(u32_t reserved); - PACK_STRUCT_FLD_S(ip6_addr_p_t target_address); - /* Options follow. */ -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** Neighbor advertisement message header. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct na_header { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t code); - PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FLD_8(u8_t flags); - PACK_STRUCT_FLD_8(u8_t reserved[3]); - PACK_STRUCT_FLD_S(ip6_addr_p_t target_address); - /* Options follow. */ -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -#define ND6_FLAG_ROUTER (0x80) -#define ND6_FLAG_SOLICITED (0x40) -#define ND6_FLAG_OVERRIDE (0x20) - -/** Router solicitation message header. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct rs_header { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t code); - PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FIELD(u32_t reserved); - /* Options follow. */ -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** Router advertisement message header. */ -#define ND6_RA_FLAG_MANAGED_ADDR_CONFIG (0x80) -#define ND6_RA_FLAG_OTHER_CONFIG (0x40) -#define ND6_RA_FLAG_HOME_AGENT (0x20) -#define ND6_RA_PREFERENCE_MASK (0x18) -#define ND6_RA_PREFERENCE_HIGH (0x08) -#define ND6_RA_PREFERENCE_MEDIUM (0x00) -#define ND6_RA_PREFERENCE_LOW (0x18) -#define ND6_RA_PREFERENCE_DISABLED (0x10) -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ra_header { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t code); - PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FLD_8(u8_t current_hop_limit); - PACK_STRUCT_FLD_8(u8_t flags); - PACK_STRUCT_FIELD(u16_t router_lifetime); - PACK_STRUCT_FIELD(u32_t reachable_time); - PACK_STRUCT_FIELD(u32_t retrans_timer); - /* Options follow. */ -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** Redirect message header. */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct redirect_header { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t code); - PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FIELD(u32_t reserved); - PACK_STRUCT_FLD_S(ip6_addr_p_t target_address); - PACK_STRUCT_FLD_S(ip6_addr_p_t destination_address); - /* Options follow. */ -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** Link-layer address option. */ -#define ND6_OPTION_TYPE_SOURCE_LLADDR (0x01) -#define ND6_OPTION_TYPE_TARGET_LLADDR (0x02) -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct lladdr_option { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t length); - PACK_STRUCT_FLD_8(u8_t addr[NETIF_MAX_HWADDR_LEN]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** Prefix information option. */ -#define ND6_OPTION_TYPE_PREFIX_INFO (0x03) -#define ND6_PREFIX_FLAG_ON_LINK (0x80) -#define ND6_PREFIX_FLAG_AUTONOMOUS (0x40) -#define ND6_PREFIX_FLAG_ROUTER_ADDRESS (0x20) -#define ND6_PREFIX_FLAG_SITE_PREFIX (0x10) -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct prefix_option { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t length); - PACK_STRUCT_FLD_8(u8_t prefix_length); - PACK_STRUCT_FLD_8(u8_t flags); - PACK_STRUCT_FIELD(u32_t valid_lifetime); - PACK_STRUCT_FIELD(u32_t preferred_lifetime); - PACK_STRUCT_FLD_8(u8_t reserved2[3]); - PACK_STRUCT_FLD_8(u8_t site_prefix_length); - PACK_STRUCT_FLD_S(ip6_addr_p_t prefix); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** Redirected header option. */ -#define ND6_OPTION_TYPE_REDIR_HDR (0x04) -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct redirected_header_option { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t length); - PACK_STRUCT_FLD_8(u8_t reserved[6]); - /* Portion of redirected packet follows. */ - /* PACK_STRUCT_FLD_8(u8_t redirected[8]); */ -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** MTU option. */ -#define ND6_OPTION_TYPE_MTU (0x05) -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct mtu_option { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t length); - PACK_STRUCT_FIELD(u16_t reserved); - PACK_STRUCT_FIELD(u32_t mtu); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** Route information option. */ -#define ND6_OPTION_TYPE_ROUTE_INFO (24) -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct route_option { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t length); - PACK_STRUCT_FLD_8(u8_t prefix_length); - PACK_STRUCT_FLD_8(u8_t preference); - PACK_STRUCT_FIELD(u32_t route_lifetime); - PACK_STRUCT_FLD_S(ip6_addr_p_t prefix); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/** Recursive DNS Server Option. */ -#define ND6_OPTION_TYPE_RDNSS (25) -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct rdnss_option { - PACK_STRUCT_FLD_8(u8_t type); - PACK_STRUCT_FLD_8(u8_t length); - PACK_STRUCT_FIELD(u16_t reserved); - PACK_STRUCT_FIELD(u32_t lifetime); - PACK_STRUCT_FLD_S(ip6_addr_p_t rdnss_address[1]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define SIZEOF_RDNSS_OPTION_BASE 8 /* size without addresses */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_ND6_H */ diff --git a/core/c/include/lwip/prot/tcp.h b/core/c/include/lwip/prot/tcp.h deleted file mode 100755 index f5a3dc8..0000000 --- a/core/c/include/lwip/prot/tcp.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @file - * TCP protocol definitions - */ - -/* - * 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_HDR_PROT_TCP_H -#define LWIP_HDR_PROT_TCP_H - -#include "lwip/arch.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Length of the TCP header, excluding options. */ -#define TCP_HLEN 20 - -/* 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 - -/* TCP header flags bits */ -#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 -/* Valid TCP header flags */ -#define TCP_FLAGS 0x3fU - -#define TCP_MAX_OPTION_BYTES 40 - -#define TCPH_HDRLEN(phdr) ((u16_t)(lwip_ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)) -#define TCPH_HDRLEN_BYTES(phdr) ((u8_t)(TCPH_HDRLEN(phdr) << 2)) -#define TCPH_FLAGS(phdr) ((u8_t)((lwip_ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS))) - -#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = lwip_htons(((len) << 12) | TCPH_FLAGS(phdr)) -#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS(~TCP_FLAGS)) | lwip_htons(flags)) -#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = (u16_t)(lwip_htons((u16_t)((len) << 12) | (flags))) - -#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | lwip_htons(flags)) -#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags & ~lwip_htons(flags)) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_TCP_H */ diff --git a/core/c/include/lwip/prot/udp.h b/core/c/include/lwip/prot/udp.h deleted file mode 100755 index 4904b7e..0000000 --- a/core/c/include/lwip/prot/udp.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file - * UDP protocol definitions - */ - -/* - * 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_HDR_PROT_UDP_H -#define LWIP_HDR_PROT_UDP_H - -#include "lwip/arch.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 - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_PROT_UDP_H */ diff --git a/core/c/include/lwip/raw.h b/core/c/include/lwip/raw.h deleted file mode 100755 index 1be1273..0000000 --- a/core/c/include/lwip/raw.h +++ /dev/null @@ -1,143 +0,0 @@ -/** - * @file - * raw API (to be used from TCPIP thread)\n - * See also @ref raw_raw - */ - -/* - * 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_HDR_RAW_H -#define LWIP_HDR_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" -#include "lwip/ip6_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define RAW_FLAGS_CONNECTED 0x01U -#define RAW_FLAGS_HDRINCL 0x02U -#define RAW_FLAGS_MULTICAST_LOOP 0x04U - -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, - const ip_addr_t *addr); - -/** the RAW protocol control block */ -struct raw_pcb { - /* Common members of all PCB types */ - IP_PCB; - - struct raw_pcb *next; - - u8_t protocol; - u8_t flags; - -#if LWIP_MULTICAST_TX_OPTIONS - /** outgoing network interface for multicast packets, by interface index (if nonzero) */ - u8_t mcast_ifindex; - /** TTL for outgoing multicast packets */ - u8_t mcast_ttl; -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - - /** receive callback function */ - raw_recv_fn recv; - /* user-supplied argument for the recv callback */ - void *recv_arg; -#if LWIP_IPV6 - /* fields for handling checksum computations as per RFC3542. */ - u16_t chksum_offset; - u8_t chksum_reqd; -#endif -}; - -/* The following functions is the application layer interface to the - RAW code. */ -struct raw_pcb * raw_new (u8_t proto); -struct raw_pcb * raw_new_ip_type(u8_t type, u8_t proto); -void raw_remove (struct raw_pcb *pcb); -err_t raw_bind (struct raw_pcb *pcb, const ip_addr_t *ipaddr); -void raw_bind_netif (struct raw_pcb *pcb, const struct netif *netif); -err_t raw_connect (struct raw_pcb *pcb, const ip_addr_t *ipaddr); -void raw_disconnect (struct raw_pcb *pcb); - -err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr); -err_t raw_sendto_if_src(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, struct netif *netif, const ip_addr_t *src_ip); -err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); - -void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); - -#define raw_flags(pcb) ((pcb)->flags) -#define raw_setflags(pcb,f) ((pcb)->flags = (f)) - -#define raw_set_flags(pcb, set_flags) do { (pcb)->flags = (u8_t)((pcb)->flags | (set_flags)); } while(0) -#define raw_clear_flags(pcb, clr_flags) do { (pcb)->flags = (u8_t)((pcb)->flags & (u8_t)(~(clr_flags) & 0xff)); } while(0) -#define raw_is_flag_set(pcb, flag) (((pcb)->flags & (flag)) != 0) - -#define raw_init() /* Compatibility define, no init needed. */ - -/* for compatibility with older implementation */ -#define raw_new_ip6(proto) raw_new_ip_type(IPADDR_TYPE_V6, proto) - -#if LWIP_MULTICAST_TX_OPTIONS -#define raw_set_multicast_netif_index(pcb, idx) ((pcb)->mcast_ifindex = (idx)) -#define raw_get_multicast_netif_index(pcb) ((pcb)->mcast_ifindex) -#define raw_set_multicast_ttl(pcb, value) ((pcb)->mcast_ttl = (value)) -#define raw_get_multicast_ttl(pcb) ((pcb)->mcast_ttl) -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_RAW */ - -#endif /* LWIP_HDR_RAW_H */ diff --git a/core/c/include/lwip/sio.h b/core/c/include/lwip/sio.h deleted file mode 100755 index efa8ade..0000000 --- a/core/c/include/lwip/sio.h +++ /dev/null @@ -1,142 +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" -#include "lwip/opt.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); -#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); -#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); -#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); -#endif - -#ifndef sio_tryread -/** - * Tries to read from the serial device. Same as sio_read but returns - * immediately if no data is available and never blocks. - * - * @param fd serial device handle - * @param data pointer to data buffer for receiving - * @param len maximum length (in bytes) of data to receive - * @return number of bytes actually received - */ -u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len); -#endif - -#ifndef sio_write -/** - * Writes to the serial device. - * - * @param fd serial device handle - * @param data pointer to data to send - * @param len length (in bytes) of data to send - * @return number of bytes actually sent - * - * @note This function will block until all data can be sent. - */ -u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len); -#endif - -#ifndef sio_read_abort -/** - * Aborts a blocking sio_read() call. - * - * @param fd serial device handle - */ -void sio_read_abort(sio_fd_t fd); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* SIO_H */ diff --git a/core/c/include/lwip/snmp.h b/core/c/include/lwip/snmp.h deleted file mode 100755 index 80e6e57..0000000 --- a/core/c/include/lwip/snmp.h +++ /dev/null @@ -1,213 +0,0 @@ -/** - * @file - * SNMP support API for implementing netifs and statitics for MIB2 - */ - -/* - * 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: Dirk Ziegelmeier - * - */ -#ifndef LWIP_HDR_SNMP_H -#define LWIP_HDR_SNMP_H - -#include "lwip/opt.h" -#include "lwip/ip_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct udp_pcb; -struct netif; - -/** - * @defgroup netif_mib2 MIB2 statistics - * @ingroup netif - */ - -/* MIB2 statistics functions */ -#if MIB2_STATS /* don't build if not configured for use in lwipopts.h */ -/** - * @ingroup netif_mib2 - * @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 -}; - -/** This macro has a precision of ~49 days because sys_now returns u32_t. \#define your own if you want ~490 days. */ -#ifndef MIB2_COPY_SYSUPTIME_TO -#define MIB2_COPY_SYSUPTIME_TO(ptrToVal) (*(ptrToVal) = (sys_now() / 10)) -#endif - -/** - * @ingroup netif_mib2 - * Increment stats member for SNMP MIB2 stats (struct stats_mib2_netif_ctrs) - */ -#define MIB2_STATS_NETIF_INC(n, x) do { ++(n)->mib2_counters.x; } while(0) -/** - * @ingroup netif_mib2 - * Add value to stats member for SNMP MIB2 stats (struct stats_mib2_netif_ctrs) - */ -#define MIB2_STATS_NETIF_ADD(n, x, val) do { (n)->mib2_counters.x += (val); } while(0) - -/** - * @ingroup netif_mib2 - * Init MIB2 statistic counters in netif - * @param netif Netif to init - * @param type one of enum @ref snmp_ifType - * @param speed your link speed here (units: bits per second) - */ -#define MIB2_INIT_NETIF(netif, type, speed) do { \ - (netif)->link_type = (type); \ - (netif)->link_speed = (speed);\ - (netif)->ts = 0; \ - (netif)->mib2_counters.ifinoctets = 0; \ - (netif)->mib2_counters.ifinucastpkts = 0; \ - (netif)->mib2_counters.ifinnucastpkts = 0; \ - (netif)->mib2_counters.ifindiscards = 0; \ - (netif)->mib2_counters.ifinerrors = 0; \ - (netif)->mib2_counters.ifinunknownprotos = 0; \ - (netif)->mib2_counters.ifoutoctets = 0; \ - (netif)->mib2_counters.ifoutucastpkts = 0; \ - (netif)->mib2_counters.ifoutnucastpkts = 0; \ - (netif)->mib2_counters.ifoutdiscards = 0; \ - (netif)->mib2_counters.ifouterrors = 0; } while(0) -#else /* MIB2_STATS */ -#ifndef MIB2_COPY_SYSUPTIME_TO -#define MIB2_COPY_SYSUPTIME_TO(ptrToVal) -#endif -#define MIB2_INIT_NETIF(netif, type, speed) -#define MIB2_STATS_NETIF_INC(n, x) -#define MIB2_STATS_NETIF_ADD(n, x, val) -#endif /* MIB2_STATS */ - -/* LWIP MIB2 callbacks */ -#if LWIP_MIB2_CALLBACKS /* don't build if not configured for use in lwipopts.h */ -/* network interface */ -void mib2_netif_added(struct netif *ni); -void mib2_netif_removed(struct netif *ni); - -#if LWIP_IPV4 && LWIP_ARP -/* ARP (for atTable and ipNetToMediaTable) */ -void mib2_add_arp_entry(struct netif *ni, ip4_addr_t *ip); -void mib2_remove_arp_entry(struct netif *ni, ip4_addr_t *ip); -#else /* LWIP_IPV4 && LWIP_ARP */ -#define mib2_add_arp_entry(ni,ip) -#define mib2_remove_arp_entry(ni,ip) -#endif /* LWIP_IPV4 && LWIP_ARP */ - -/* IP */ -#if LWIP_IPV4 -void mib2_add_ip4(struct netif *ni); -void mib2_remove_ip4(struct netif *ni); -void mib2_add_route_ip4(u8_t dflt, struct netif *ni); -void mib2_remove_route_ip4(u8_t dflt, struct netif *ni); -#endif /* LWIP_IPV4 */ - -/* UDP */ -#if LWIP_UDP -void mib2_udp_bind(struct udp_pcb *pcb); -void mib2_udp_unbind(struct udp_pcb *pcb); -#endif /* LWIP_UDP */ - -#else /* LWIP_MIB2_CALLBACKS */ -/* LWIP_MIB2_CALLBACKS support not available */ -/* define everything to be empty */ - -/* network interface */ -#define mib2_netif_added(ni) -#define mib2_netif_removed(ni) - -/* ARP */ -#define mib2_add_arp_entry(ni,ip) -#define mib2_remove_arp_entry(ni,ip) - -/* IP */ -#define mib2_add_ip4(ni) -#define mib2_remove_ip4(ni) -#define mib2_add_route_ip4(dflt, ni) -#define mib2_remove_route_ip4(dflt, ni) - -/* UDP */ -#define mib2_udp_bind(pcb) -#define mib2_udp_unbind(pcb) -#endif /* LWIP_MIB2_CALLBACKS */ - -/* for source-code compatibility reasons only, can be removed (not used internally) */ -#define NETIF_INIT_SNMP MIB2_INIT_NETIF -#define snmp_add_ifinoctets(ni,value) MIB2_STATS_NETIF_ADD(ni, ifinoctets, value) -#define snmp_inc_ifinucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifinucastpkts) -#define snmp_inc_ifinnucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifinnucastpkts) -#define snmp_inc_ifindiscards(ni) MIB2_STATS_NETIF_INC(ni, ifindiscards) -#define snmp_inc_ifinerrors(ni) MIB2_STATS_NETIF_INC(ni, ifinerrors) -#define snmp_inc_ifinunknownprotos(ni) MIB2_STATS_NETIF_INC(ni, ifinunknownprotos) -#define snmp_add_ifoutoctets(ni,value) MIB2_STATS_NETIF_ADD(ni, ifoutoctets, value) -#define snmp_inc_ifoutucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifoutucastpkts) -#define snmp_inc_ifoutnucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifoutnucastpkts) -#define snmp_inc_ifoutdiscards(ni) MIB2_STATS_NETIF_INC(ni, ifoutdiscards) -#define snmp_inc_ifouterrors(ni) MIB2_STATS_NETIF_INC(ni, ifouterrors) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_SNMP_H */ diff --git a/core/c/include/lwip/sockets.h b/core/c/include/lwip/sockets.h deleted file mode 100755 index f448591..0000000 --- a/core/c/include/lwip/sockets.h +++ /dev/null @@ -1,688 +0,0 @@ -/** - * @file - * Socket API (to be used from non-TCPIP threads) - */ - -/* - * 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_HDR_SOCKETS_H -#define LWIP_HDR_SOCKETS_H - -#include "lwip/opt.h" - -#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/err.h" -#include "lwip/inet.h" -#include "lwip/errno.h" - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED - to prevent this code from redefining it. */ -#if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED) -typedef u8_t sa_family_t; -#endif -/* If your port already typedef's in_port_t, define IN_PORT_T_DEFINED - to prevent this code from redefining it. */ -#if !defined(in_port_t) && !defined(IN_PORT_T_DEFINED) -typedef u16_t in_port_t; -#endif - -#if LWIP_IPV4 -/* members are in network byte order */ -struct sockaddr_in { - u8_t sin_len; - sa_family_t sin_family; - in_port_t sin_port; - struct in_addr sin_addr; -#define SIN_ZERO_LEN 8 - char sin_zero[SIN_ZERO_LEN]; -}; -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6 -struct sockaddr_in6 { - u8_t sin6_len; /* length of this structure */ - sa_family_t sin6_family; /* AF_INET6 */ - in_port_t sin6_port; /* Transport layer port # */ - u32_t sin6_flowinfo; /* IPv6 flow information */ - struct in6_addr sin6_addr; /* IPv6 address */ - u32_t sin6_scope_id; /* Set of interfaces for scope */ -}; -#endif /* LWIP_IPV6 */ - -struct sockaddr { - u8_t sa_len; - sa_family_t sa_family; - char sa_data[14]; -}; - -struct sockaddr_storage { - u8_t s2_len; - sa_family_t ss_family; - char s2_data1[2]; - u32_t s2_data2[3]; -#if LWIP_IPV6 - u32_t s2_data3[3]; -#endif /* LWIP_IPV6 */ -}; - -/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED - to prevent this code from redefining it. */ -#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED) -typedef u32_t socklen_t; -#endif - -#if !defined IOV_MAX -#define IOV_MAX 0xFFFF -#elif IOV_MAX > 0xFFFF -#error "IOV_MAX larger than supported by LwIP" -#endif /* IOV_MAX */ - -#if !defined(iovec) -struct iovec { - void *iov_base; - size_t iov_len; -}; -#endif - -struct msghdr { - void *msg_name; - socklen_t msg_namelen; - struct iovec *msg_iov; - int msg_iovlen; - void *msg_control; - socklen_t msg_controllen; - int msg_flags; -}; - -/* struct msghdr->msg_flags bit field values */ -#define MSG_TRUNC 0x04 -#define MSG_CTRUNC 0x08 - -/* RFC 3542, Section 20: Ancillary Data */ -struct cmsghdr { - socklen_t cmsg_len; /* number of bytes, including header */ - int cmsg_level; /* originating protocol */ - int cmsg_type; /* protocol-specific type */ -}; -/* Data section follows header and possible padding, typically referred to as - unsigned char cmsg_data[]; */ - -/* cmsg header/data alignment. NOTE: we align to native word size (double word -size on 16-bit arch) so structures are not placed at an unaligned address. -16-bit arch needs double word to ensure 32-bit alignment because socklen_t -could be 32 bits. If we ever have cmsg data with a 64-bit variable, alignment -will need to increase long long */ -#define ALIGN_H(size) (((size) + sizeof(long) - 1U) & ~(sizeof(long)-1U)) -#define ALIGN_D(size) ALIGN_H(size) - -#define CMSG_FIRSTHDR(mhdr) \ - ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ - (struct cmsghdr *)(mhdr)->msg_control : \ - (struct cmsghdr *)NULL) - -#define CMSG_NXTHDR(mhdr, cmsg) \ - (((cmsg) == NULL) ? CMSG_FIRSTHDR(mhdr) : \ - (((u8_t *)(cmsg) + ALIGN_H((cmsg)->cmsg_len) \ - + ALIGN_D(sizeof(struct cmsghdr)) > \ - (u8_t *)((mhdr)->msg_control) + (mhdr)->msg_controllen) ? \ - (struct cmsghdr *)NULL : \ - (struct cmsghdr *)((void*)((u8_t *)(cmsg) + \ - ALIGN_H((cmsg)->cmsg_len))))) - -#define CMSG_DATA(cmsg) ((void*)((u8_t *)(cmsg) + \ - ALIGN_D(sizeof(struct cmsghdr)))) - -#define CMSG_SPACE(length) (ALIGN_D(sizeof(struct cmsghdr)) + \ - ALIGN_H(length)) - -#define CMSG_LEN(length) (ALIGN_D(sizeof(struct cmsghdr)) + \ - length) - -/* Set socket options argument */ -#define IFNAMSIZ NETIF_NAMESIZE -struct ifreq { - char ifr_name[IFNAMSIZ]; /* Interface name */ -}; - -/* 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_REUSEADDR 0x0004 /* Allow local address reuse */ -#define SO_KEEPALIVE 0x0008 /* keep connections alive */ -#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ - - -/* - * Additional options, not kept in so_options. - */ -#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ -#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ -#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ -#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ -#define SO_LINGER 0x0080 /* linger on close if data present */ -#define SO_DONTLINGER ((int)(~SO_LINGER)) -#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ -#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ -#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 /* 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 */ -#define SO_BINDTODEVICE 0x100b /* bind to device */ - -/* - * Structure used for manipulating linger option. - */ -struct linger { - int l_onoff; /* option on/off */ - int l_linger; /* linger time in seconds */ -}; - -/* - * 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 -#if LWIP_IPV6 -#define AF_INET6 10 -#else /* LWIP_IPV6 */ -#define AF_INET6 AF_UNSPEC -#endif /* LWIP_IPV6 */ -#define PF_INET AF_INET -#define PF_INET6 AF_INET6 -#define PF_UNSPEC AF_UNSPEC - -#define IPPROTO_IP 0 -#define IPPROTO_ICMP 1 -#define IPPROTO_TCP 6 -#define IPPROTO_UDP 17 -#if LWIP_IPV6 -#define IPPROTO_IPV6 41 -#define IPPROTO_ICMPV6 58 -#endif /* LWIP_IPV6 */ -#define IPPROTO_UDPLITE 136 -#define IPPROTO_RAW 255 - -/* 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 */ -#define MSG_NOSIGNAL 0x20 /* Uninmplemented: Requests not to send the SIGPIPE signal if an attempt to send is made on a stream-oriented socket that is no longer connected. */ - - -/* - * Options for level IPPROTO_IP - */ -#define IP_TOS 1 -#define IP_TTL 2 -#define IP_PKTINFO 8 - -#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_IPV6 -/* - * Options for level IPPROTO_IPV6 - */ -#define IPV6_CHECKSUM 7 /* RFC3542: calculate and insert the ICMPv6 checksum for raw sockets. */ -#define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */ -#endif /* LWIP_IPV6 */ - -#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_MULTICAST_TX_OPTIONS -/* - * Options and types for UDP multicast traffic handling - */ -#define IP_MULTICAST_TTL 5 -#define IP_MULTICAST_IF 6 -#define IP_MULTICAST_LOOP 7 -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - -#if LWIP_IGMP -/* - * Options and types related to multicast membership - */ -#define IP_ADD_MEMBERSHIP 3 -#define IP_DROP_MEMBERSHIP 4 - -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 */ - -#if LWIP_IPV4 -struct in_pktinfo { - unsigned int ipi_ifindex; /* Interface index */ - struct in_addr ipi_addr; /* Destination (from header) address */ -}; -#endif /* LWIP_IPV4 */ - -#if LWIP_IPV6_MLD -/* - * Options and types related to IPv6 multicast membership - */ -#define IPV6_JOIN_GROUP 12 -#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP -#define IPV6_LEAVE_GROUP 13 -#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP - -typedef struct ipv6_mreq { - struct in6_addr ipv6mr_multiaddr; /* IPv6 multicast addr */ - unsigned int ipv6mr_interface; /* interface index, or 0 */ -} ipv6_mreq; -#endif /* LWIP_IPV6_MLD */ - -/* - * 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) ((long)(IOC_VOID|((x)<<8)|(y))) - -#define _IOR(x,y,t) ((long)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))) - -#define _IOW(x,y,t) ((long)(IOC_IN|((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 O_NONBLOCK /* same as O_NONBLOCK, for compatibility */ -#endif -#ifndef O_RDONLY -#define O_RDONLY 2 -#endif -#ifndef O_WRONLY -#define O_WRONLY 4 -#endif -#ifndef O_RDWR -#define O_RDWR (O_RDONLY|O_WRONLY) -#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 LWIP_SELECT_MAXNFDS (FD_SETSIZE + LWIP_SOCKET_OFFSET) -#define FDSETSAFESET(n, code) do { \ - if (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0)) { \ - code; }} while(0) -#define FDSETSAFEGET(n, code) (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0) ?\ - (code) : 0) -#define FD_SET(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] = (u8_t)((p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] | (1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))) -#define FD_CLR(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] = (u8_t)((p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] & ~(1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))) -#define FD_ISSET(n,p) FDSETSAFEGET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] & (1 << (((n)-LWIP_SOCKET_OFFSET) & 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; - -#elif FD_SETSIZE < (LWIP_SOCKET_OFFSET + MEMP_NUM_NETCONN) -#error "external FD_SETSIZE too small for number of sockets" -#else -#define LWIP_SELECT_MAXNFDS FD_SETSIZE -#endif /* FD_SET */ - -/* poll-related defines and types */ -/* @todo: find a better way to guard the definition of these defines and types if already defined */ -#if !defined(POLLIN) && !defined(POLLOUT) -#define POLLIN 0x1 -#define POLLOUT 0x2 -#define POLLERR 0x4 -#define POLLNVAL 0x8 -/* Below values are unimplemented */ -#define POLLRDNORM 0x10 -#define POLLRDBAND 0x20 -#define POLLPRI 0x40 -#define POLLWRNORM 0x80 -#define POLLWRBAND 0x100 -#define POLLHUP 0x200 -typedef unsigned int nfds_t; -struct pollfd -{ - int fd; - short events; - short revents; -}; -#endif - -/** 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 */ - -#define lwip_socket_init() /* Compatibility define, no init needed. */ -void lwip_socket_thread_init(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ -void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ - -#if LWIP_COMPAT_SOCKETS == 2 -/* This helps code parsers/code completion by not having the COMPAT functions as defines */ -#define lwip_accept accept -#define lwip_bind bind -#define lwip_shutdown shutdown -#define lwip_getpeername getpeername -#define lwip_getsockname getsockname -#define lwip_setsockopt setsockopt -#define lwip_getsockopt getsockopt -#define lwip_close closesocket -#define lwip_connect connect -#define lwip_listen listen -#define lwip_recv recv -#define lwip_recvmsg recvmsg -#define lwip_recvfrom recvfrom -#define lwip_send send -#define lwip_sendmsg sendmsg -#define lwip_sendto sendto -#define lwip_socket socket -#if LWIP_SOCKET_SELECT -#define lwip_select select -#endif -#if LWIP_SOCKET_POLL -#define lwip_poll poll -#endif -#define lwip_ioctl ioctlsocket -#define lwip_inet_ntop inet_ntop -#define lwip_inet_pton inet_pton - -#if LWIP_POSIX_SOCKETS_IO_NAMES -#define lwip_read read -#define lwip_readv readv -#define lwip_write write -#define lwip_writev writev -#undef lwip_close -#define lwip_close close -#define closesocket(s) close(s) -int fcntl(int s, int cmd, ...); -#undef lwip_ioctl -#define lwip_ioctl ioctl -#define ioctlsocket ioctl -#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ -#endif /* LWIP_COMPAT_SOCKETS == 2 */ - -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); -ssize_t lwip_recv(int s, void *mem, size_t len, int flags); -ssize_t lwip_read(int s, void *mem, size_t len); -ssize_t lwip_readv(int s, const struct iovec *iov, int iovcnt); -ssize_t lwip_recvfrom(int s, void *mem, size_t len, int flags, - struct sockaddr *from, socklen_t *fromlen); -ssize_t lwip_recvmsg(int s, struct msghdr *message, int flags); -ssize_t lwip_send(int s, const void *dataptr, size_t size, int flags); -ssize_t lwip_sendmsg(int s, const struct msghdr *message, int flags); -ssize_t 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); -ssize_t lwip_write(int s, const void *dataptr, size_t size); -ssize_t lwip_writev(int s, const struct iovec *iov, int iovcnt); -#if LWIP_SOCKET_SELECT -int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, - struct timeval *timeout); -#endif -#if LWIP_SOCKET_POLL -int lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout); -#endif -int lwip_ioctl(int s, long cmd, void *argp); -int lwip_fcntl(int s, int cmd, int val); -const char *lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size); -int lwip_inet_pton(int af, const char *src, void *dst); - -#if LWIP_COMPAT_SOCKETS -#if LWIP_COMPAT_SOCKETS != 2 -/** @ingroup socket */ -#define accept(s,addr,addrlen) lwip_accept(s,addr,addrlen) -/** @ingroup socket */ -#define bind(s,name,namelen) lwip_bind(s,name,namelen) -/** @ingroup socket */ -#define shutdown(s,how) lwip_shutdown(s,how) -/** @ingroup socket */ -#define getpeername(s,name,namelen) lwip_getpeername(s,name,namelen) -/** @ingroup socket */ -#define getsockname(s,name,namelen) lwip_getsockname(s,name,namelen) -/** @ingroup socket */ -#define setsockopt(s,level,optname,opval,optlen) lwip_setsockopt(s,level,optname,opval,optlen) -/** @ingroup socket */ -#define getsockopt(s,level,optname,opval,optlen) lwip_getsockopt(s,level,optname,opval,optlen) -/** @ingroup socket */ -#define closesocket(s) lwip_close(s) -/** @ingroup socket */ -#define connect(s,name,namelen) lwip_connect(s,name,namelen) -/** @ingroup socket */ -#define listen(s,backlog) lwip_listen(s,backlog) -/** @ingroup socket */ -#define recv(s,mem,len,flags) lwip_recv(s,mem,len,flags) -/** @ingroup socket */ -#define recvmsg(s,message,flags) lwip_recvmsg(s,message,flags) -/** @ingroup socket */ -#define recvfrom(s,mem,len,flags,from,fromlen) lwip_recvfrom(s,mem,len,flags,from,fromlen) -/** @ingroup socket */ -#define send(s,dataptr,size,flags) lwip_send(s,dataptr,size,flags) -/** @ingroup socket */ -#define sendmsg(s,message,flags) lwip_sendmsg(s,message,flags) -/** @ingroup socket */ -#define sendto(s,dataptr,size,flags,to,tolen) lwip_sendto(s,dataptr,size,flags,to,tolen) -/** @ingroup socket */ -#define socket(domain,type,protocol) lwip_socket(domain,type,protocol) -#if LWIP_SOCKET_SELECT -/** @ingroup socket */ -#define select(maxfdp1,readset,writeset,exceptset,timeout) lwip_select(maxfdp1,readset,writeset,exceptset,timeout) -#endif -#if LWIP_SOCKET_POLL -/** @ingroup socket */ -#define poll(fds,nfds,timeout) lwip_poll(fds,nfds,timeout) -#endif -/** @ingroup socket */ -#define ioctlsocket(s,cmd,argp) lwip_ioctl(s,cmd,argp) -/** @ingroup socket */ -#define inet_ntop(af,src,dst,size) lwip_inet_ntop(af,src,dst,size) -/** @ingroup socket */ -#define inet_pton(af,src,dst) lwip_inet_pton(af,src,dst) - -#if LWIP_POSIX_SOCKETS_IO_NAMES -/** @ingroup socket */ -#define read(s,mem,len) lwip_read(s,mem,len) -/** @ingroup socket */ -#define readv(s,iov,iovcnt) lwip_readv(s,iov,iovcnt) -/** @ingroup socket */ -#define write(s,dataptr,len) lwip_write(s,dataptr,len) -/** @ingroup socket */ -#define writev(s,iov,iovcnt) lwip_writev(s,iov,iovcnt) -/** @ingroup socket */ -#define close(s) lwip_close(s) -/** @ingroup socket */ -#define fcntl(s,cmd,val) lwip_fcntl(s,cmd,val) -/** @ingroup socket */ -#define ioctl(s,cmd,argp) lwip_ioctl(s,cmd,argp) -#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ -#endif /* LWIP_COMPAT_SOCKETS != 2 */ - -#endif /* LWIP_COMPAT_SOCKETS */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_SOCKET */ - -#endif /* LWIP_HDR_SOCKETS_H */ diff --git a/core/c/include/lwip/stats.h b/core/c/include/lwip/stats.h deleted file mode 100755 index 1cf4e59..0000000 --- a/core/c/include/lwip/stats.h +++ /dev/null @@ -1,491 +0,0 @@ -/** - * @file - * Statistics API (to be used from TCPIP thread) - */ - -/* - * 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_HDR_STATS_H -#define LWIP_HDR_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 - -/** Protocol related stats */ -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; -}; - -/** IGMP stats */ -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. */ -}; - -/** Memory stats */ -struct stats_mem { -#if defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY - const char *name; -#endif /* defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY */ - STAT_COUNTER err; - mem_size_t avail; - mem_size_t used; - mem_size_t max; - STAT_COUNTER illegal; -}; - -/** System element stats */ -struct stats_syselem { - STAT_COUNTER used; - STAT_COUNTER max; - STAT_COUNTER err; -}; - -/** System stats */ -struct stats_sys { - struct stats_syselem sem; - struct stats_syselem mutex; - struct stats_syselem mbox; -}; - -/** SNMP MIB2 stats */ -struct stats_mib2 { - /* IP */ - u32_t ipinhdrerrors; - u32_t ipinaddrerrors; - u32_t ipinunknownprotos; - u32_t ipindiscards; - u32_t ipindelivers; - u32_t ipoutrequests; - u32_t ipoutdiscards; - u32_t ipoutnoroutes; - u32_t ipreasmoks; - u32_t ipreasmfails; - u32_t ipfragoks; - u32_t ipfragfails; - u32_t ipfragcreates; - u32_t ipreasmreqds; - u32_t ipforwdatagrams; - u32_t ipinreceives; - - /* TCP */ - u32_t tcpactiveopens; - u32_t tcppassiveopens; - u32_t tcpattemptfails; - u32_t tcpestabresets; - u32_t tcpoutsegs; - u32_t tcpretranssegs; - u32_t tcpinsegs; - u32_t tcpinerrs; - u32_t tcpoutrsts; - - /* UDP */ - u32_t udpindatagrams; - u32_t udpnoports; - u32_t udpinerrors; - u32_t udpoutdatagrams; - - /* ICMP */ - u32_t icmpinmsgs; - u32_t icmpinerrors; - u32_t icmpindestunreachs; - u32_t icmpintimeexcds; - u32_t icmpinparmprobs; - u32_t icmpinsrcquenchs; - u32_t icmpinredirects; - u32_t icmpinechos; - u32_t icmpinechoreps; - u32_t icmpintimestamps; - u32_t icmpintimestampreps; - u32_t icmpinaddrmasks; - u32_t icmpinaddrmaskreps; - u32_t icmpoutmsgs; - u32_t icmpouterrors; - u32_t icmpoutdestunreachs; - u32_t icmpouttimeexcds; - u32_t icmpoutechos; /* can be incremented by user application ('ping') */ - u32_t icmpoutechoreps; -}; - -/** - * @ingroup netif_mib2 - * SNMP MIB2 interface stats - */ -struct stats_mib2_netif_ctrs { - /** The total number of octets received on the interface, including framing characters */ - u32_t ifinoctets; - /** The number of packets, delivered by this sub-layer to a higher (sub-)layer, which were - * not addressed to a multicast or broadcast address at this sub-layer */ - u32_t ifinucastpkts; - /** The number of packets, delivered by this sub-layer to a higher (sub-)layer, which were - * addressed to a multicast or broadcast address at this sub-layer */ - u32_t ifinnucastpkts; - /** The number of inbound packets which were chosen to be discarded even though no errors had - * been detected to prevent their being deliverable to a higher-layer protocol. One possible - * reason for discarding such a packet could be to free up buffer space */ - u32_t ifindiscards; - /** For packet-oriented interfaces, the number of inbound packets that contained errors - * preventing them from being deliverable to a higher-layer protocol. For character- - * oriented or fixed-length interfaces, the number of inbound transmission units that - * contained errors preventing them from being deliverable to a higher-layer protocol. */ - u32_t ifinerrors; - /** For packet-oriented interfaces, the number of packets received via the interface which - * were discarded because of an unknown or unsupported protocol. For character-oriented - * or fixed-length interfaces that support protocol multiplexing the number of transmission - * units received via the interface which were discarded because of an unknown or unsupported - * protocol. For any interface that does not support protocol multiplexing, this counter will - * always be 0 */ - u32_t ifinunknownprotos; - /** The total number of octets transmitted out of the interface, including framing characters. */ - u32_t ifoutoctets; - /** The total number of packets that higher-level protocols requested be transmitted, and - * which were not addressed to a multicast or broadcast address at this sub-layer, including - * those that were discarded or not sent. */ - u32_t ifoutucastpkts; - /** The total number of packets that higher-level protocols requested be transmitted, and which - * were addressed to a multicast or broadcast address at this sub-layer, including - * those that were discarded or not sent. */ - u32_t ifoutnucastpkts; - /** The number of outbound packets which were chosen to be discarded even though no errors had - * been detected to prevent their being transmitted. One possible reason for discarding - * such a packet could be to free up buffer space. */ - u32_t ifoutdiscards; - /** For packet-oriented interfaces, the number of outbound packets that could not be transmitted - * because of errors. For character-oriented or fixed-length interfaces, the number of outbound - * transmission units that could not be transmitted because of errors. */ - u32_t ifouterrors; -}; - -/** lwIP stats container */ -struct stats_ { -#if LINK_STATS - /** Link level */ - struct stats_proto link; -#endif -#if ETHARP_STATS - /** ARP */ - struct stats_proto etharp; -#endif -#if IPFRAG_STATS - /** Fragmentation */ - struct stats_proto ip_frag; -#endif -#if IP_STATS - /** IP */ - struct stats_proto ip; -#endif -#if ICMP_STATS - /** ICMP */ - struct stats_proto icmp; -#endif -#if IGMP_STATS - /** IGMP */ - struct stats_igmp igmp; -#endif -#if UDP_STATS - /** UDP */ - struct stats_proto udp; -#endif -#if TCP_STATS - /** TCP */ - struct stats_proto tcp; -#endif -#if MEM_STATS - /** Heap */ - struct stats_mem mem; -#endif -#if MEMP_STATS - /** Internal memory pools */ - struct stats_mem *memp[MEMP_MAX]; -#endif -#if SYS_STATS - /** System */ - struct stats_sys sys; -#endif -#if IP6_STATS - /** IPv6 */ - struct stats_proto ip6; -#endif -#if ICMP6_STATS - /** ICMP6 */ - struct stats_proto icmp6; -#endif -#if IP6_FRAG_STATS - /** IPv6 fragmentation */ - struct stats_proto ip6_frag; -#endif -#if MLD6_STATS - /** Multicast listener discovery */ - struct stats_igmp mld6; -#endif -#if ND6_STATS - /** Neighbor discovery */ - struct stats_proto nd6; -#endif -#if MIB2_STATS - /** SNMP MIB2 */ - struct stats_mib2 mib2; -#endif -}; - -/** Global variable containing lwIP internal statistics. Add this to your debugger's watchlist. */ -extern struct stats_ lwip_stats; - -/** Init statistics */ -void stats_init(void); - -#define STATS_INC(x) ++lwip_stats.x -#define STATS_DEC(x) --lwip_stats.x -#define STATS_INC_USED(x, y, type) do { lwip_stats.x.used = (type)(lwip_stats.x.used + y); \ - if (lwip_stats.x.max < lwip_stats.x.used) { \ - lwip_stats.x.max = lwip_stats.x.used; \ - } \ - } while(0) -#define STATS_GET(x) lwip_stats.x -#else /* LWIP_STATS */ -#define stats_init() -#define STATS_INC(x) -#define STATS_DEC(x) -#define STATS_INC_USED(x, y, type) -#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, "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, mem_size_t) -#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x = (mem_size_t)((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_DEC(x, i) STATS_DEC(memp[i]->x) -#define MEMP_STATS_DISPLAY(i) stats_display_memp(lwip_stats.memp[i], i) -#define MEMP_STATS_GET(x, i) STATS_GET(memp[i]->x) - #else -#define MEMP_STATS_DEC(x, i) -#define MEMP_STATS_DISPLAY(i) -#define MEMP_STATS_GET(x, i) 0 -#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, STAT_COUNTER) -#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 - -#if IP6_STATS -#define IP6_STATS_INC(x) STATS_INC(x) -#define IP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6, "IPv6") -#else -#define IP6_STATS_INC(x) -#define IP6_STATS_DISPLAY() -#endif - -#if ICMP6_STATS -#define ICMP6_STATS_INC(x) STATS_INC(x) -#define ICMP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp6, "ICMPv6") -#else -#define ICMP6_STATS_INC(x) -#define ICMP6_STATS_DISPLAY() -#endif - -#if IP6_FRAG_STATS -#define IP6_FRAG_STATS_INC(x) STATS_INC(x) -#define IP6_FRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6_frag, "IPv6 FRAG") -#else -#define IP6_FRAG_STATS_INC(x) -#define IP6_FRAG_STATS_DISPLAY() -#endif - -#if MLD6_STATS -#define MLD6_STATS_INC(x) STATS_INC(x) -#define MLD6_STATS_DISPLAY() stats_display_igmp(&lwip_stats.mld6, "MLDv1") -#else -#define MLD6_STATS_INC(x) -#define MLD6_STATS_DISPLAY() -#endif - -#if ND6_STATS -#define ND6_STATS_INC(x) STATS_INC(x) -#define ND6_STATS_DISPLAY() stats_display_proto(&lwip_stats.nd6, "ND") -#else -#define ND6_STATS_INC(x) -#define ND6_STATS_DISPLAY() -#endif - -#if MIB2_STATS -#define MIB2_STATS_INC(x) STATS_INC(x) -#else -#define MIB2_STATS_INC(x) -#endif - -/* Display of statistics */ -#if LWIP_STATS_DISPLAY -void stats_display(void); -void stats_display_proto(struct stats_proto *proto, const char *name); -void stats_display_igmp(struct stats_igmp *igmp, const char *name); -void stats_display_mem(struct stats_mem *mem, const char *name); -void stats_display_memp(struct stats_mem *mem, int index); -void stats_display_sys(struct stats_sys *sys); -#else /* LWIP_STATS_DISPLAY */ -#define stats_display() -#define stats_display_proto(proto, name) -#define stats_display_igmp(igmp, name) -#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_HDR_STATS_H */ diff --git a/core/c/include/lwip/sys.h b/core/c/include/lwip/sys.h deleted file mode 100755 index cd83470..0000000 --- a/core/c/include/lwip/sys.h +++ /dev/null @@ -1,560 +0,0 @@ -/** - * @file - * OS abstraction layer - */ - -/* - * 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_HDR_SYS_H -#define LWIP_HDR_SYS_H - -#include "lwip/opt.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_sem_valid(s) 0 -#define sys_sem_valid_val(s) 0 -#define sys_sem_set_invalid(s) -#define sys_sem_set_invalid_val(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_mutex_valid(mu) 0 -#define sys_mutex_set_invalid(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_mbox_valid(m) -#define sys_mbox_valid_val(m) -#define sys_mbox_set_invalid(m) -#define sys_mbox_set_invalid_val(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 */ -#ifndef LWIP_COMPAT_MUTEX -#define LWIP_COMPAT_MUTEX 0 -#endif - -#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 */ - -/** - * @ingroup sys_mutex - * Create a new mutex. - * Note that mutexes are expected to not be taken recursively by the lwIP code, - * so both implementation types (recursive or non-recursive) should work. - * The mutex is allocated to the memory that 'mutex' - * points to (which can be both a pointer or the actual OS structure). - * If the mutex has been created, ERR_OK should be returned. Returning any - * other error will provide a hint what went wrong, but except for assertions, - * no real error handling is implemented. - * - * @param mutex pointer to the mutex to create - * @return ERR_OK if successful, another err_t otherwise - */ -err_t sys_mutex_new(sys_mutex_t *mutex); -/** - * @ingroup sys_mutex - * Blocks the thread until the mutex can be grabbed. - * @param mutex the mutex to lock - */ -void sys_mutex_lock(sys_mutex_t *mutex); -/** - * @ingroup sys_mutex - * Releases the mutex previously locked through 'sys_mutex_lock()'. - * @param mutex the mutex to unlock - */ -void sys_mutex_unlock(sys_mutex_t *mutex); -/** - * @ingroup sys_mutex - * Deallocates a mutex. - * @param mutex the mutex to delete - */ -void sys_mutex_free(sys_mutex_t *mutex); -#ifndef sys_mutex_valid -/** - * @ingroup sys_mutex - * Returns 1 if the mutes is valid, 0 if it is not valid. - * When using pointers, a simple way is to check the pointer for != NULL. - * When directly using OS structures, implementing this may be more complex. - * This may also be a define, in which case the function is not prototyped. - */ -int sys_mutex_valid(sys_mutex_t *mutex); -#endif -#ifndef sys_mutex_set_invalid -/** - * @ingroup sys_mutex - * Invalidate a mutex so that sys_mutex_valid() returns 0. - * ATTENTION: This does NOT mean that the mutex shall be deallocated: - * sys_mutex_free() is always called before calling this function! - * This may also be a define, in which case the function is not prototyped. - */ -void sys_mutex_set_invalid(sys_mutex_t *mutex); -#endif -#endif /* LWIP_COMPAT_MUTEX */ - -/* Semaphore functions: */ - -/** - * @ingroup sys_sem - * Create a new semaphore - * Creates a new semaphore. The semaphore is allocated to the memory that 'sem' - * points to (which can be both a pointer or the actual OS structure). - * The "count" argument specifies the initial state of the semaphore (which is - * either 0 or 1). - * If the semaphore has been created, ERR_OK should be returned. Returning any - * other error will provide a hint what went wrong, but except for assertions, - * no real error handling is implemented. - * - * @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); -/** - * @ingroup sys_sem - * Signals a semaphore - * @param sem the semaphore to signal - */ -void sys_sem_signal(sys_sem_t *sem); -/** - * @ingroup sys_sem - * Blocks the thread while waiting for the semaphore to be signaled. If the - * "timeout" argument is non-zero, the thread should only be blocked for the - * specified time (measured in milliseconds). If the "timeout" argument is zero, - * the thread should be blocked until the semaphore is signalled. - * - * The return value is SYS_ARCH_TIMEOUT if the semaphore wasn't signaled within - * the specified time or any other value if it was signaled (with or without - * waiting). - * Notice that lwIP implements a function with a similar name, - * sys_sem_wait(), that uses the sys_arch_sem_wait() function. - * - * @param sem the semaphore to wait for - * @param timeout timeout in milliseconds to wait (0 = wait forever) - * @return SYS_ARCH_TIMEOUT on timeout, any other value on success - */ -u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout); -/** - * @ingroup sys_sem - * Deallocates 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 -/** - * @ingroup sys_sem - * Returns 1 if the semaphore is valid, 0 if it is not valid. - * When using pointers, a simple way is to check the pointer for != NULL. - * When directly using OS structures, implementing this may be more complex. - * This may also be a define, in which case the function is not prototyped. - */ -int sys_sem_valid(sys_sem_t *sem); -#endif -#ifndef sys_sem_set_invalid -/** - * @ingroup sys_sem - * Invalidate a semaphore so that sys_sem_valid() returns 0. - * ATTENTION: This does NOT mean that the semaphore shall be deallocated: - * sys_sem_free() is always called before calling this function! - * This may also be a define, in which case the function is not prototyped. - */ -void sys_sem_set_invalid(sys_sem_t *sem); -#endif -#ifndef sys_sem_valid_val -/** - * Same as sys_sem_valid() but taking a value, not a pointer - */ -#define sys_sem_valid_val(sem) sys_sem_valid(&(sem)) -#endif -#ifndef sys_sem_set_invalid_val -/** - * Same as sys_sem_set_invalid() but taking a value, not a pointer - */ -#define sys_sem_set_invalid_val(sem) sys_sem_set_invalid(&(sem)) -#endif - -#ifndef sys_msleep -/** - * @ingroup sys_misc - * Sleep for specified number of ms - */ -void sys_msleep(u32_t ms); /* only has a (close to) 1 ms resolution. */ -#endif - -/* Mailbox functions. */ - -/** - * @ingroup sys_mbox - * Creates an empty mailbox for maximum "size" elements. Elements stored - * in mailboxes are pointers. You have to define macros "_MBOX_SIZE" - * in your lwipopts.h, or ignore this parameter in your implementation - * and use a default size. - * If the mailbox has been created, ERR_OK should be returned. Returning any - * other error will provide a hint what went wrong, but except for assertions, - * no real error handling is implemented. - * - * @param mbox pointer to the mbox to create - * @param size (minimum) 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); -/** - * @ingroup sys_mbox - * Post a message to an mbox - may not fail - * -> blocks if full, only to be 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); -/** - * @ingroup sys_mbox - * Try to post a message to an mbox - may fail if full. - * Can be used from ISR (if the sys arch layer allows this). - * Returns ERR_MEM if it is full, else, ERR_OK if the "msg" is posted. - * - * @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); -/** - * @ingroup sys_mbox - * Try to post a message to an mbox - may fail if full. - * To be be used from ISR. - * Returns ERR_MEM if it is full, else, ERR_OK if the "msg" is posted. - * - * @param mbox mbox to posts the message - * @param msg message to post (ATTENTION: can be NULL) - */ -err_t sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg); -/** - * @ingroup sys_mbox - * Blocks the thread until a message arrives in the mailbox, but does - * not block the thread longer than "timeout" milliseconds (similar to - * the sys_arch_sem_wait() function). If "timeout" is 0, the thread should - * be blocked until a message arrives. The "msg" argument is a result - * parameter that is set by the function (i.e., by doing "*msg = - * ptr"). The "msg" parameter maybe NULL to indicate that the message - * should be dropped. - * The return values are the same as for the sys_arch_sem_wait() function: - * SYS_ARCH_TIMEOUT if there was a timeout, any other value if a messages - * is received. - * - * Note that a function with a similar name, sys_mbox_fetch(), is - * implemented by lwIP. - * - * @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 (0 = wait forever) - * @return SYS_ARCH_TIMEOUT on timeout, any other value if a message has been received - */ -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 timeout for sys_arch_mbox_fetch() */ -#ifndef sys_arch_mbox_tryfetch -/** - * @ingroup sys_mbox - * This is similar to sys_arch_mbox_fetch, however if a message is not - * present in the mailbox, it immediately returns with the code - * SYS_MBOX_EMPTY. On success 0 is returned. - * To allow for efficient implementations, this can be defined as a - * function-like macro in sys_arch.h instead of a normal function. For - * example, a naive implementation could be: - * \#define sys_arch_mbox_tryfetch(mbox,msg) sys_arch_mbox_fetch(mbox,msg,1) - * although this would introduce unnecessary delays. - * - * @param mbox mbox to get a message from - * @param msg pointer where the message is stored - * @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) -/** - * @ingroup sys_mbox - * Deallocates a mailbox. If there are messages still present in the - * mailbox when the mailbox is deallocated, it is an indication of a - * programming error in lwIP and the developer should be notified. - * - * @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 -/** - * @ingroup sys_mbox - * Returns 1 if the mailbox is valid, 0 if it is not valid. - * When using pointers, a simple way is to check the pointer for != NULL. - * When directly using OS structures, implementing this may be more complex. - * This may also be a define, in which case the function is not prototyped. - */ -int sys_mbox_valid(sys_mbox_t *mbox); -#endif -#ifndef sys_mbox_set_invalid -/** - * @ingroup sys_mbox - * Invalidate a mailbox so that sys_mbox_valid() returns 0. - * ATTENTION: This does NOT mean that the mailbox shall be deallocated: - * sys_mbox_free() is always called before calling this function! - * This may also be a define, in which case the function is not prototyped. - */ -void sys_mbox_set_invalid(sys_mbox_t *mbox); -#endif -#ifndef sys_mbox_valid_val -/** - * Same as sys_mbox_valid() but taking a value, not a pointer - */ -#define sys_mbox_valid_val(mbox) sys_mbox_valid(&(mbox)) -#endif -#ifndef sys_mbox_set_invalid_val -/** - * Same as sys_mbox_set_invalid() but taking a value, not a pointer - */ -#define sys_mbox_set_invalid_val(mbox) sys_mbox_set_invalid(&(mbox)) -#endif - - -/** - * @ingroup sys_misc - * The only thread function: - * Starts a new thread named "name" with priority "prio" that will begin its - * execution in the function "thread()". The "arg" argument will be passed as an - * argument to the thread() function. The stack size to used for this thread is - * the "stacksize" parameter. The id of the new thread is returned. Both the id - * and the priority are system dependent. - * ATTENTION: although this function returns a value, it MUST NOT FAIL (ports have to assert this!) - * - * @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 */ - -/** - * @ingroup sys_misc - * sys_init() must be called before anything else. - * Initialize the sys_arch layer. - */ -void sys_init(void); - -#ifndef sys_jiffies -/** - * Ticks/jiffies since power up. - */ -u32_t sys_jiffies(void); -#endif - -/** - * @ingroup sys_time - * Returns the current time in milliseconds, - * may be the same as sys_jiffies or at least based on it. - * Don't care for wraparound, this is only used for time diffs. - * Not implementing this function means you cannot use some modules (e.g. TCP - * timestamps, internal timeouts for NO_SYS==1). - */ -u32_t sys_now(void); - -/* 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 - -/** - * @ingroup sys_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 -/** - * @ingroup sys_prot - * 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() -/** - * @ingroup sys_prot - * 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); -void sys_arch_unprotect(sys_prot_t pval); - -#else - -#define SYS_ARCH_DECL_PROTECT(lev) -#define SYS_ARCH_PROTECT(lev) -#define SYS_ARCH_UNPROTECT(lev) - -#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 */ - -#ifndef SYS_ARCH_LOCKED -#define SYS_ARCH_LOCKED(code) do { \ - SYS_ARCH_DECL_PROTECT(old_level); \ - SYS_ARCH_PROTECT(old_level); \ - code; \ - SYS_ARCH_UNPROTECT(old_level); \ - } while(0) -#endif /* SYS_ARCH_LOCKED */ - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_SYS_H */ diff --git a/core/c/include/lwip/tcp.h b/core/c/include/lwip/tcp.h deleted file mode 100755 index 24a7f12..0000000 --- a/core/c/include/lwip/tcp.h +++ /dev/null @@ -1,502 +0,0 @@ -/** - * @file - * TCP API (to be used from TCPIP thread)\n - * See also @ref tcp_raw - */ - -/* - * 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_HDR_TCP_H -#define LWIP_HDR_TCP_H - -#include "lwip/opt.h" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/tcpbase.h" -#include "lwip/mem.h" -#include "lwip/pbuf.h" -#include "lwip/ip.h" -#include "lwip/icmp.h" -#include "lwip/err.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct tcp_pcb; -struct tcp_pcb_listen; - -/** 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); - -#if LWIP_WND_SCALE -#define RCV_WND_SCALE(pcb, wnd) (((wnd) >> (pcb)->rcv_scale)) -#define SND_WND_SCALE(pcb, wnd) (((wnd) << (pcb)->snd_scale)) -#define TCPWND16(x) ((u16_t)LWIP_MIN((x), 0xFFFF)) -#define TCP_WND_MAX(pcb) ((tcpwnd_size_t)(((pcb)->flags & TF_WND_SCALE) ? TCP_WND : TCPWND16(TCP_WND))) -#else -#define RCV_WND_SCALE(pcb, wnd) (wnd) -#define SND_WND_SCALE(pcb, wnd) (wnd) -#define TCPWND16(x) (x) -#define TCP_WND_MAX(pcb) TCP_WND -#endif -/* Increments a tcpwnd_size_t and holds at max value rather than rollover */ -#define TCP_WND_INC(wnd, inc) do { \ - if ((tcpwnd_size_t)(wnd + inc) >= wnd) { \ - wnd = (tcpwnd_size_t)(wnd + inc); \ - } else { \ - wnd = (tcpwnd_size_t)-1; \ - } \ - } while(0) - -#if LWIP_TCP_SACK_OUT -/** SACK ranges to include in ACK packets. - * SACK entry is invalid if left==right. */ -struct tcp_sack_range { - /** Left edge of the SACK: the first acknowledged sequence number. */ - u32_t left; - /** Right edge of the SACK: the last acknowledged sequence number +1 (so first NOT acknowledged). */ - u32_t right; -}; -#endif /* LWIP_TCP_SACK_OUT */ - -/** Function prototype for deallocation of arguments. Called *just before* the - * pcb is freed, so don't expect to be able to do anything with this pcb! - * - * @param id ext arg id (allocated via @ref tcp_ext_arg_alloc_id) - * @param data pointer to the data (set via @ref tcp_ext_arg_set before) - */ -typedef void (*tcp_extarg_callback_pcb_destroyed_fn)(u8_t id, void *data); - -/** Function prototype to transition arguments from a listening pcb to an accepted pcb - * - * @param id ext arg id (allocated via @ref tcp_ext_arg_alloc_id) - * @param lpcb the listening pcb accepting a connection - * @param cpcb the newly allocated connection pcb - * @return ERR_OK if OK, any error if connection should be dropped - */ -typedef err_t (*tcp_extarg_callback_passive_open_fn)(u8_t id, struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb); - -/** A table of callback functions that is invoked for ext arguments */ -struct tcp_ext_arg_callbacks { - /** @ref tcp_extarg_callback_pcb_destroyed_fn */ - tcp_extarg_callback_pcb_destroyed_fn destroy; - /** @ref tcp_extarg_callback_passive_open_fn */ - tcp_extarg_callback_passive_open_fn passive_open; -}; - -#define LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID 0xFF - -#if LWIP_TCP_PCB_NUM_EXT_ARGS -/* This is the structure for ext args in tcp pcbs (used as array) */ -struct tcp_pcb_ext_args { - const struct tcp_ext_arg_callbacks *callbacks; - void *data; -}; -/* This is a helper define to prevent zero size arrays if disabled */ -#define TCP_PCB_EXTARGS struct tcp_pcb_ext_args ext_args[LWIP_TCP_PCB_NUM_EXT_ARGS]; -#else -#define TCP_PCB_EXTARGS -#endif - -typedef u16_t tcpflags_t; -#define TCP_ALLFLAGS 0xffffU - -/** - * members common to struct tcp_pcb and struct tcp_listen_pcb - */ -#define TCP_PCB_COMMON(type) \ - type *next; /* for the linked list */ \ - void *callback_arg; \ - TCP_PCB_EXTARGS \ - enum tcp_state state; /* TCP state */ \ - u8_t prio; \ - /* ports are in host byte order */ \ - u16_t local_port - - -/** the TCP protocol control block for listening pcbs */ -struct tcp_pcb_listen { -/** Common members of all PCB types */ - IP_PCB; -/** Protocol specific PCB members */ - TCP_PCB_COMMON(struct tcp_pcb_listen); - -#if LWIP_CALLBACK_API - /* Function to call when a listener has been connected. */ - tcp_accept_fn accept; -#endif /* LWIP_CALLBACK_API */ - -#if TCP_LISTEN_BACKLOG - u8_t backlog; - u8_t accepts_pending; -#endif /* TCP_LISTEN_BACKLOG */ -}; - - -/** 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; - - tcpflags_t flags; -#define TF_ACK_DELAY 0x01U /* Delayed ACK. */ -#define TF_ACK_NOW 0x02U /* Immediate ACK. */ -#define TF_INFR 0x04U /* In fast recovery. */ -#define TF_CLOSEPEND 0x08U /* If this is set, tcp_close failed to enqueue the FIN (retried in tcp_tmr) */ -#define TF_RXCLOSED 0x10U /* rx closed by tcp_shutdown */ -#define TF_FIN 0x20U /* Connection was closed locally (FIN segment enqueued). */ -#define TF_NODELAY 0x40U /* Disable Nagle algorithm */ -#define TF_NAGLEMEMERR 0x80U /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ -#if LWIP_WND_SCALE -#define TF_WND_SCALE 0x0100U /* Window Scale option enabled */ -#endif -#if TCP_LISTEN_BACKLOG -#define TF_BACKLOGPEND 0x0200U /* If this is set, a connection pcb has increased the backlog on its listener */ -#endif -#if LWIP_TCP_TIMESTAMPS -#define TF_TIMESTAMP 0x0400U /* Timestamp option enabled */ -#endif -#define TF_RTO 0x0800U /* RTO timer has fired, in-flight data moved to unsent and being retransmitted */ -#if LWIP_TCP_SACK_OUT -#define TF_SACK 0x1000U /* Selective ACKs enabled */ -#endif - - /* the rest of the fields are in host byte order - as we have to do some math with them */ - - /* Timers */ - u8_t polltmr, pollinterval; - u8_t last_timer; - u32_t tmr; - - /* receiver variables */ - u32_t rcv_nxt; /* next seqno expected */ - tcpwnd_size_t rcv_wnd; /* receiver window available */ - tcpwnd_size_t rcv_ann_wnd; /* receiver window to announce */ - u32_t rcv_ann_right_edge; /* announced right edge of window */ - -#if LWIP_TCP_SACK_OUT - /* SACK ranges to include in ACK packets (entry is invalid if left==right) */ - struct tcp_sack_range rcv_sacks[LWIP_TCP_MAX_SACK_NUM]; -#define LWIP_TCP_SACK_VALID(pcb, idx) ((pcb)->rcv_sacks[idx].left != (pcb)->rcv_sacks[idx].right) -#endif /* LWIP_TCP_SACK_OUT */ - - /* 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; /* @see "Congestion Avoidance and Control" by Van Jacobson and Karels */ - - s16_t rto; /* retransmission time-out (in ticks of TCP_SLOW_INTERVAL) */ - u8_t nrtx; /* number of retransmissions */ - - /* fast retransmit/recovery */ - u8_t dupacks; - u32_t lastack; /* Highest acknowledged seqno. */ - - /* congestion avoidance/control variables */ - tcpwnd_size_t cwnd; - tcpwnd_size_t ssthresh; - - /* first byte following last rto byte */ - u32_t rto_end; - - /* sender variables */ - u32_t snd_nxt; /* next new seqno to be sent */ - 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. */ - tcpwnd_size_t snd_wnd; /* sender window */ - tcpwnd_size_t snd_wnd_max; /* the maximum sender window announced by the remote host */ - - tcpwnd_size_t snd_buf; /* Available buffer space for sending (in bytes). */ -#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3) - u16_t snd_queuelen; /* Number of pbufs currently in the send buffer. */ - -#if TCP_OVERSIZE - /* Extra bytes available at the end of the last pbuf in unsent. */ - u16_t unsent_oversize; -#endif /* TCP_OVERSIZE */ - - tcpwnd_size_t bytes_acked; - - /* 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 || TCP_LISTEN_BACKLOG - struct tcp_pcb_listen* listener; -#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ - -#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 */ - u8_t persist_cnt; - /* Persist timer back-off */ - u8_t persist_backoff; - /* Number of persist probes */ - u8_t persist_probe; - - /* KEEPALIVE counter */ - u8_t keep_cnt_sent; - -#if LWIP_WND_SCALE - u8_t snd_scale; - u8_t rcv_scale; -#endif -}; - -#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); -struct tcp_pcb * tcp_new_ip_type (u8_t type); - -void tcp_arg (struct tcp_pcb *pcb, void *arg); -#if LWIP_CALLBACK_API -void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv); -void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent); -void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err); -void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept); -#endif /* LWIP_CALLBACK_API */ -void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval); - -#define tcp_set_flags(pcb, set_flags) do { (pcb)->flags = (tcpflags_t)((pcb)->flags | (set_flags)); } while(0) -#define tcp_clear_flags(pcb, clr_flags) do { (pcb)->flags = (tcpflags_t)((pcb)->flags & (tcpflags_t)(~(clr_flags) & TCP_ALLFLAGS)); } while(0) -#define tcp_is_flag_set(pcb, flag) (((pcb)->flags & (flag)) != 0) - -#if LWIP_TCP_TIMESTAMPS -#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) -#else /* LWIP_TCP_TIMESTAMPS */ -/** @ingroup tcp_raw */ -#define tcp_mss(pcb) ((pcb)->mss) -#endif /* LWIP_TCP_TIMESTAMPS */ -/** @ingroup tcp_raw */ -#define tcp_sndbuf(pcb) (TCPWND16((pcb)->snd_buf)) -/** @ingroup tcp_raw */ -#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen) -/** @ingroup tcp_raw */ -#define tcp_nagle_disable(pcb) tcp_set_flags(pcb, TF_NODELAY) -/** @ingroup tcp_raw */ -#define tcp_nagle_enable(pcb) tcp_clear_flags(pcb, TF_NODELAY) -/** @ingroup tcp_raw */ -#define tcp_nagle_disabled(pcb) tcp_is_flag_set(pcb, TF_NODELAY) - -#if TCP_LISTEN_BACKLOG -#define tcp_backlog_set(pcb, new_backlog) do { \ - LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", (pcb)->state == LISTEN); \ - ((struct tcp_pcb_listen *)(pcb))->backlog = ((new_backlog) ? (new_backlog) : 1); } while(0) -void tcp_backlog_delayed(struct tcp_pcb* pcb); -void tcp_backlog_accepted(struct tcp_pcb* pcb); -#else /* TCP_LISTEN_BACKLOG */ -#define tcp_backlog_set(pcb, new_backlog) -#define tcp_backlog_delayed(pcb) -#define tcp_backlog_accepted(pcb) -#endif /* TCP_LISTEN_BACKLOG */ -#define tcp_accepted(pcb) do { LWIP_UNUSED_ARG(pcb); } while(0) /* compatibility define, not needed any more */ - -void tcp_recved (struct tcp_pcb *pcb, u16_t len); -err_t tcp_bind (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, - u16_t port); -void tcp_bind_netif(struct tcp_pcb *pcb, const struct netif *netif); -err_t tcp_connect (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, - u16_t port, tcp_connected_fn connected); - -struct tcp_pcb * tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err); -struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); -/** @ingroup tcp_raw */ -#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) - -void tcp_abort (struct tcp_pcb *pcb); -err_t tcp_close (struct tcp_pcb *pcb); -err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx); - -err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, - u8_t apiflags); - -void tcp_setprio (struct tcp_pcb *pcb, u8_t prio); - -err_t tcp_output (struct tcp_pcb *pcb); - -err_t tcp_tcp_get_tcp_addrinfo(struct tcp_pcb *pcb, int local, ip_addr_t *addr, u16_t *port); - -err_t tcp_process_refused_data(struct tcp_pcb *pcb); - -#define tcp_dbg_get_tcp_state(pcb) ((pcb)->state) - -/* for compatibility with older implementation */ -#define tcp_new_ip6() tcp_new_ip_type(IPADDR_TYPE_V6) - -#if LWIP_TCP_PCB_NUM_EXT_ARGS -u8_t tcp_ext_arg_alloc_id(void); -void tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, uint8_t id, const struct tcp_ext_arg_callbacks * const callbacks); -void tcp_ext_arg_set(struct tcp_pcb *pcb, uint8_t id, void *arg); -void *tcp_ext_arg_get(const struct tcp_pcb *pcb, uint8_t id); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_TCP */ - -#endif /* LWIP_HDR_TCP_H */ diff --git a/core/c/include/lwip/tcpbase.h b/core/c/include/lwip/tcpbase.h deleted file mode 100755 index 6614b80..0000000 --- a/core/c/include/lwip/tcpbase.h +++ /dev/null @@ -1,88 +0,0 @@ -/** - * @file - * Base TCP API definitions shared by TCP and ALTCP\n - * See also @ref tcp_raw - */ - -/* - * 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_HDR_TCPBASE_H -#define LWIP_HDR_TCPBASE_H - -#include "lwip/opt.h" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#ifdef __cplusplus -extern "C" { -#endif - - -#if LWIP_WND_SCALE -typedef u32_t tcpwnd_size_t; -#else -typedef u16_t tcpwnd_size_t; -#endif - -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 -}; -/* ATTENTION: this depends on state number ordering! */ -#define TCP_STATE_IS_CLOSING(state) ((state) >= FIN_WAIT_1) - -/* Flags for "apiflags" parameter in tcp_write */ -#define TCP_WRITE_FLAG_COPY 0x01 -#define TCP_WRITE_FLAG_MORE 0x02 - -#define TCP_PRIO_MIN 1 -#define TCP_PRIO_NORMAL 64 -#define TCP_PRIO_MAX 127 - -const char* tcp_debug_state_str(enum tcp_state s); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_TCP */ - -#endif /* LWIP_HDR_TCPBASE_H */ diff --git a/core/c/include/lwip/tcpip.h b/core/c/include/lwip/tcpip.h deleted file mode 100755 index ec14701..0000000 --- a/core/c/include/lwip/tcpip.h +++ /dev/null @@ -1,113 +0,0 @@ -/** - * @file - * Functions to sync with TCPIP thread - */ - -/* - * 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_HDR_TCPIP_H -#define LWIP_HDR_TCPIP_H - -#include "lwip/opt.h" - -#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/err.h" -#include "lwip/timeouts.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_TCPIP_CORE_LOCKING -/** The global semaphore to lock the stack. */ -extern sys_mutex_t lock_tcpip_core; -#if !defined LOCK_TCPIP_CORE || defined __DOXYGEN__ -/** Lock lwIP core mutex (needs @ref LWIP_TCPIP_CORE_LOCKING 1) */ -#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) -/** Unlock lwIP core mutex (needs @ref LWIP_TCPIP_CORE_LOCKING 1) */ -#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core) -#endif /* LOCK_TCPIP_CORE */ -#else /* LWIP_TCPIP_CORE_LOCKING */ -#define LOCK_TCPIP_CORE() -#define UNLOCK_TCPIP_CORE() -#endif /* LWIP_TCPIP_CORE_LOCKING */ - -struct pbuf; -struct netif; - -/** 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); - -/* Forward declarations */ -struct tcpip_callback_msg; - -void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg); - -err_t tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn); -err_t tcpip_input(struct pbuf *p, struct netif *inp); - -err_t tcpip_try_callback(tcpip_callback_fn function, void *ctx); -err_t tcpip_callback(tcpip_callback_fn function, void *ctx); -/** @ingroup lwip_os - * @deprecated use tcpip_try_callback() or tcpip_callback() instead - */ -#define tcpip_callback_with_block(function, ctx, block) ((block != 0)? tcpip_callback(function, ctx) : tcpip_try_callback(function, ctx)) - -struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx); -void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg); -err_t tcpip_callbackmsg_trycallback(struct tcpip_callback_msg* msg); -err_t tcpip_callbackmsg_trycallback_fromisr(struct tcpip_callback_msg* msg); - -/* 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 && LWIP_TIMERS -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 && LWIP_TIMERS */ - -#ifdef TCPIP_THREAD_TEST -int tcpip_thread_poll_one(void); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !NO_SYS */ - -#endif /* LWIP_HDR_TCPIP_H */ diff --git a/core/c/include/lwip/timeouts.h b/core/c/include/lwip/timeouts.h deleted file mode 100755 index 3ab3c0e..0000000 --- a/core/c/include/lwip/timeouts.h +++ /dev/null @@ -1,128 +0,0 @@ -/** - * @file - * Timer implementations - */ - -/* - * 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_HDR_TIMEOUTS_H -#define LWIP_HDR_TIMEOUTS_H - -#include "lwip/opt.h" -#include "lwip/err.h" -#if !NO_SYS -#include "lwip/sys.h" -#endif - -#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 - -/** Returned by sys_timeouts_sleeptime() to indicate there is no timer, so we - * can sleep forever. - */ -#define SYS_TIMEOUTS_SLEEPTIME_INFINITE 0xFFFFFFFF - -/** Function prototype for a stack-internal timer function that has to be - * called at a defined interval */ -typedef void (* lwip_cyclic_timer_handler)(void); - -/** This struct contains information about a stack-internal timer function - that has to be called at a defined interval */ -struct lwip_cyclic_timer { - u32_t interval_ms; - lwip_cyclic_timer_handler handler; -#if LWIP_DEBUG_TIMERNAMES - const char* handler_name; -#endif /* LWIP_DEBUG_TIMERNAMES */ -}; - -/** This array contains all stack-internal cyclic timers. To get the number of - * timers, use lwip_num_cyclic_timers */ -extern const struct lwip_cyclic_timer lwip_cyclic_timers[]; -/** Array size of lwip_cyclic_timers[] */ -extern const int lwip_num_cyclic_timers; - -#if LWIP_TIMERS - -/** Function prototype for a timeout callback function. Register such a function - * using sys_timeout(). - * - * @param arg Additional argument to pass to the function - set up by sys_timeout() - */ -typedef void (* sys_timeout_handler)(void *arg); - -struct sys_timeo { - struct sys_timeo *next; - u32_t time; - sys_timeout_handler h; - void *arg; -#if LWIP_DEBUG_TIMERNAMES - const char* handler_name; -#endif /* LWIP_DEBUG_TIMERNAMES */ -}; - -void sys_timeouts_init(void); - -#if LWIP_DEBUG_TIMERNAMES -void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name); -#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler) -#else /* LWIP_DEBUG_TIMERNAMES */ -void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg); -#endif /* LWIP_DEBUG_TIMERNAMES */ - -void sys_untimeout(sys_timeout_handler handler, void *arg); -void sys_restart_timeouts(void); -void sys_check_timeouts(void); -u32_t sys_timeouts_sleeptime(void); - -#if LWIP_TESTMODE -struct sys_timeo** sys_timeouts_get_next_timeout(void); -void lwip_cyclic_timer(void *arg); -#endif - -#endif /* LWIP_TIMERS */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_TIMEOUTS_H */ diff --git a/core/c/include/lwip/udp.h b/core/c/include/lwip/udp.h deleted file mode 100755 index 759cf16..0000000 --- a/core/c/include/lwip/udp.h +++ /dev/null @@ -1,232 +0,0 @@ -/** - * @file - * UDP API (to be used from TCPIP thread)\n - * See also @ref udp_raw - */ - -/* - * 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_HDR_UDP_H -#define LWIP_HDR_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" -#include "lwip/ip6_addr.h" -#include "lwip/prot/udp.h" - -#ifdef __cplusplus -extern "C" { -#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' might point into the pbuf 'p' so freeing this pbuf - * can make '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 - */ -#if TUN2SOCKS -typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *addr, u16_t port, const ip_addr_t *dest_addr, u16_t dest_port); -#else -typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *addr, u16_t port); -#endif /* TUN2SOCKS */ - -/** the UDP protocol control block */ -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_MULTICAST_TX_OPTIONS -#if LWIP_IPV4 - /** outgoing network interface for multicast packets, by IPv4 address (if not 'any') */ - ip4_addr_t mcast_ip4; -#endif /* LWIP_IPV4 */ - /** outgoing network interface for multicast packets, by interface index (if nonzero) */ - u8_t mcast_ifindex; - /** TTL for outgoing multicast packets */ - u8_t mcast_ttl; -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - -#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 external 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); -struct udp_pcb * udp_new_ip_type(u8_t type); -void udp_remove (struct udp_pcb *pcb); -err_t udp_bind (struct udp_pcb *pcb, const ip_addr_t *ipaddr, - u16_t port); -void udp_bind_netif (struct udp_pcb *pcb, const struct netif* netif); -err_t udp_connect (struct udp_pcb *pcb, const ip_addr_t *ipaddr, - u16_t port); -void udp_disconnect (struct udp_pcb *pcb); -void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, - void *recv_arg); -#if TUN2SOCKS -err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, - struct netif *netif, - const ip_addr_t *src_ip, u16_t src_port); -err_t udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, - struct netif *netif, - const ip_addr_t *src_ip, u16_t src_port); -err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, - const ip_addr_t *src_ip, u16_t src_port); -#else -err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, - struct netif *netif); -err_t udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, - struct netif *netif, const ip_addr_t *src_ip); -err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port); -#endif /* TUN2SOCKS */ -err_t udp_send (struct udp_pcb *pcb, struct pbuf *p); - -#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP -#if TUN2SOCKS -err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, - struct netif *netif, u8_t have_chksum, - u16_t chksum, - const ip_addr_t *src_ip, u16_t src_port); -err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, - u8_t have_chksum, u16_t chksum, - const ip_addr_t *src_ip, u16_t src_port); -#else -err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, - struct netif *netif, u8_t have_chksum, - u16_t chksum); -err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, - u8_t have_chksum, u16_t chksum); -#endif /* TUN2SOCKS */ -err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, - u8_t have_chksum, u16_t chksum); -#if TUN2SOCKS -err_t udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, - u8_t have_chksum, u16_t chksum, const ip_addr_t *src_ip, u16_t src_port); -#else -err_t udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, - const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, - u8_t have_chksum, u16_t chksum, const ip_addr_t *src_ip); -#endif /* TUN2SOCKS */ -#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - -#define udp_flags(pcb) ((pcb)->flags) -#define udp_setflags(pcb, f) ((pcb)->flags = (f)) - -#define udp_set_flags(pcb, set_flags) do { (pcb)->flags = (u8_t)((pcb)->flags | (set_flags)); } while(0) -#define udp_clear_flags(pcb, clr_flags) do { (pcb)->flags = (u8_t)((pcb)->flags & (u8_t)(~(clr_flags) & 0xff)); } while(0) -#define udp_is_flag_set(pcb, flag) (((pcb)->flags & (flag)) != 0) - -/* The following functions are the lower layer interface to UDP. */ -void udp_input (struct pbuf *p, struct netif *inp); - -void udp_init (void); - -/* for compatibility with older implementation */ -#define udp_new_ip6() udp_new_ip_type(IPADDR_TYPE_V6) - -#if LWIP_MULTICAST_TX_OPTIONS -#if LWIP_IPV4 -#define udp_set_multicast_netif_addr(pcb, ip4addr) ip4_addr_copy((pcb)->mcast_ip4, *(ip4addr)) -#define udp_get_multicast_netif_addr(pcb) (&(pcb)->mcast_ip4) -#endif /* LWIP_IPV4 */ -#define udp_set_multicast_netif_index(pcb, idx) ((pcb)->mcast_ifindex = (idx)) -#define udp_get_multicast_netif_index(pcb) ((pcb)->mcast_ifindex) -#define udp_set_multicast_ttl(pcb, value) ((pcb)->mcast_ttl = (value)) -#define udp_get_multicast_ttl(pcb) ((pcb)->mcast_ttl) -#endif /* LWIP_MULTICAST_TX_OPTIONS */ - -#if UDP_DEBUG -void udp_debug_print(struct udp_hdr *udphdr); -#else -#define udp_debug_print(udphdr) -#endif - -void udp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_UDP */ - -#endif /* LWIP_HDR_UDP_H */ diff --git a/core/c/include/netif/bridgeif.h b/core/c/include/netif/bridgeif.h deleted file mode 100755 index 927c619..0000000 --- a/core/c/include/netif/bridgeif.h +++ /dev/null @@ -1,127 +0,0 @@ -/** - * @file - * lwIP netif implementing an IEEE 802.1D MAC Bridge - */ - -/* - * Copyright (c) 2017 Simon Goldschmidt. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ -#ifndef LWIP_HDR_NETIF_BRIDGEIF_H -#define LWIP_HDR_NETIF_BRIDGEIF_H - -#include "netif/bridgeif_opts.h" - -#include "lwip/err.h" -#include "lwip/prot/ethernet.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct netif; - -#if (BRIDGEIF_MAX_PORTS < 0) || (BRIDGEIF_MAX_PORTS >= 64) -#error BRIDGEIF_MAX_PORTS must be [1..63] -#elif BRIDGEIF_MAX_PORTS < 8 -typedef u8_t bridgeif_portmask_t; -#elif BRIDGEIF_MAX_PORTS < 16 -typedef u16_t bridgeif_portmask_t; -#elif BRIDGEIF_MAX_PORTS < 32 -typedef u32_t bridgeif_portmask_t; -#elif BRIDGEIF_MAX_PORTS < 64 -typedef u64_t bridgeif_portmask_t; -#endif - -#define BR_FLOOD ((bridgeif_portmask_t)-1) - -/** @ingroup bridgeif - * Initialisation data for @ref bridgeif_init. - * An instance of this type must be passed as parameter 'state' to @ref netif_add - * when the bridge is added. - */ -typedef struct bridgeif_initdata_s { - /** MAC address of the bridge (cannot use the netif's addresses) */ - struct eth_addr ethaddr; - /** Maximum number of ports in the bridge (ports are stored in an array, this - influences memory allocated for netif->state of the bridge netif). */ - u8_t max_ports; - /** Maximum number of dynamic/learning entries in the bridge's forwarding database. - In the default implementation, this controls memory consumption only. */ - u16_t max_fdb_dynamic_entries; - /** Maximum number of static forwarding entries. Influences memory consumption! */ - u16_t max_fdb_static_entries; -} bridgeif_initdata_t; - -/** @ingroup bridgeif - * Use this for constant initialization of a bridgeif_initdat_t - * (ethaddr must be passed as ETH_ADDR()) - */ -#define BRIDGEIF_INITDATA1(max_ports, max_fdb_dynamic_entries, max_fdb_static_entries, ethaddr) {ethaddr, max_ports, max_fdb_dynamic_entries, max_fdb_static_entries} -/** @ingroup bridgeif - * Use this for constant initialization of a bridgeif_initdat_t - * (each byte of ethaddr must be passed) - */ -#define BRIDGEIF_INITDATA2(max_ports, max_fdb_dynamic_entries, max_fdb_static_entries, e0, e1, e2, e3, e4, e5) {{e0, e1, e2, e3, e4, e5}, max_ports, max_fdb_dynamic_entries, max_fdb_static_entries} - -err_t bridgeif_init(struct netif *netif); -err_t bridgeif_add_port(struct netif *bridgeif, struct netif *portif); -err_t bridgeif_fdb_add(struct netif *bridgeif, const struct eth_addr *addr, bridgeif_portmask_t ports); -err_t bridgeif_fdb_remove(struct netif *bridgeif, const struct eth_addr *addr); - -/* FDB interface, can be replaced by own implementation */ -void bridgeif_fdb_update_src(void *fdb_ptr, struct eth_addr *src_addr, u8_t port_idx); -bridgeif_portmask_t bridgeif_fdb_get_dst_ports(void *fdb_ptr, struct eth_addr *dst_addr); -void* bridgeif_fdb_init(u16_t max_fdb_entries); - -#if BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT -#ifndef BRIDGEIF_DECL_PROTECT -/* define bridgeif protection to sys_arch_protect... */ -#include "lwip/sys.h" -#define BRIDGEIF_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev) -#define BRIDGEIF_READ_PROTECT(lev) SYS_ARCH_PROTECT(lev) -#define BRIDGEIF_READ_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev) -#define BRIDGEIF_WRITE_PROTECT(lev) -#define BRIDGEIF_WRITE_UNPROTECT(lev) -#endif -#else /* BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT */ -#include "lwip/tcpip.h" -#define BRIDGEIF_DECL_PROTECT(lev) -#define BRIDGEIF_READ_PROTECT(lev) -#define BRIDGEIF_READ_UNPROTECT(lev) -#define BRIDGEIF_WRITE_PROTECT(lev) -#define BRIDGEIF_WRITE_UNPROTECT(lev) -#endif /* BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_NETIF_BRIDGEIF_H */ diff --git a/core/c/include/netif/bridgeif_opts.h b/core/c/include/netif/bridgeif_opts.h deleted file mode 100755 index 5866410..0000000 --- a/core/c/include/netif/bridgeif_opts.h +++ /dev/null @@ -1,90 +0,0 @@ -/** - * @file - * lwIP netif implementing an IEEE 802.1D MAC Bridge - */ - -/* - * Copyright (c) 2017 Simon Goldschmidt. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ - -#ifndef LWIP_HDR_NETIF_BRIDGEIF_OPTS_H -#define LWIP_HDR_NETIF_BRIDGEIF_OPTS_H - -#include "lwip/opt.h" - -/** - * @defgroup bridgeif_opts Options - * @ingroup bridgeif - * @{ - */ - -/** BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT==1: set port netif's 'input' function - * to call directly into bridgeif code and on top of that, directly call into - * the selected forwarding port's 'linkoutput' function. - * This means that the bridgeif input/output path is protected from concurrent access - * but as well, *all* bridge port netif's drivers must correctly handle concurrent access! - * == 0: get into tcpip_thread for every input packet (no multithreading) - * ATTENTION: as ==0 relies on tcpip.h, the default depends on NO_SYS setting - */ -#ifndef BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT -#define BRIDGEIF_PORT_NETIFS_OUTPUT_DIRECT NO_SYS -#endif - -/** BRIDGEIF_MAX_PORTS: this is used to create a typedef used for forwarding - * bit-fields: the number of bits required is this + 1 (for the internal/cpu port) - * (63 is the maximum, resulting in an u64_t for the bit mask) - * ATTENTION: this controls the maximum number of the implementation only! - * The max. number of ports per bridge must still be passed via netif_add parameter! - */ -#ifndef BRIDGEIF_MAX_PORTS -#define BRIDGEIF_MAX_PORTS 7 -#endif - -/** BRIDGEIF_DEBUG: Enable generic debugging in bridgeif.c. */ -#ifndef BRIDGEIF_DEBUG -#define BRIDGEIF_DEBUG LWIP_DBG_OFF -#endif - -/** BRIDGEIF_DEBUG: Enable FDB debugging in bridgeif.c. */ -#ifndef BRIDGEIF_FDB_DEBUG -#define BRIDGEIF_FDB_DEBUG LWIP_DBG_OFF -#endif - -/** BRIDGEIF_DEBUG: Enable forwarding debugging in bridgeif.c. */ -#ifndef BRIDGEIF_FW_DEBUG -#define BRIDGEIF_FW_DEBUG LWIP_DBG_OFF -#endif - -/** - * @} - */ - -#endif /* LWIP_HDR_NETIF_BRIDGEIF_OPTS_H */ diff --git a/core/c/include/netif/etharp.h b/core/c/include/netif/etharp.h deleted file mode 100755 index c00de04..0000000 --- a/core/c/include/netif/etharp.h +++ /dev/null @@ -1,3 +0,0 @@ -/* ARP has been moved to core/ipv4, provide this #include for compatibility only */ -#include "lwip/etharp.h" -#include "netif/ethernet.h" diff --git a/core/c/include/netif/ethernet.h b/core/c/include/netif/ethernet.h deleted file mode 100755 index 6e94e16..0000000 --- a/core/c/include/netif/ethernet.h +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @file - * Ethernet input function - handles INCOMING ethernet level traffic - * To be used in most low-level netif implementations - */ - -/* - * 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 LWIP_HDR_NETIF_ETHERNET_H -#define LWIP_HDR_NETIF_ETHERNET_H - -#include "lwip/opt.h" - -#include "lwip/pbuf.h" -#include "lwip/netif.h" -#include "lwip/prot/ethernet.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if LWIP_ARP || LWIP_ETHERNET - -/** 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 - -err_t ethernet_input(struct pbuf *p, struct netif *netif); -err_t ethernet_output(struct netif* netif, struct pbuf* p, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type); - -extern const struct eth_addr ethbroadcast, ethzero; - -#endif /* LWIP_ARP || LWIP_ETHERNET */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_NETIF_ETHERNET_H */ diff --git a/core/c/include/netif/ieee802154.h b/core/c/include/netif/ieee802154.h deleted file mode 100755 index 0a11a2b..0000000 --- a/core/c/include/netif/ieee802154.h +++ /dev/null @@ -1,112 +0,0 @@ -/** - * @file - * Definitions for IEEE 802.15.4 MAC frames - */ - -/* - * Copyright (c) 2018 Simon Goldschmidt. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ -#ifndef LWIP_HDR_NETIF_IEEE802154_H -#define LWIP_HDR_NETIF_IEEE802154_H - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** General MAC frame format - * This shows the full featured header, mainly for documentation. - * Some fields are omitted or shortened to achieve frame compression. - */ -struct ieee_802154_hdr { - /** See IEEE_802154_FC_* defines */ - PACK_STRUCT_FIELD(u16_t frame_control); - /** Sequence number is omitted if IEEE_802154_FC_SEQNO_SUPPR is set in frame_control */ - PACK_STRUCT_FLD_8(u8_t sequence_number); - /** Destination PAN ID is omitted if Destination Addressing Mode is 0 */ - PACK_STRUCT_FIELD(u16_t destination_pan_id); - /** Destination Address is omitted if Destination Addressing Mode is 0 */ - PACK_STRUCT_FLD_8(u8_t destination_address[8]); - /** Source PAN ID is omitted if Source Addressing Mode is 0 - or if IEEE_802154_FC_PANID_COMPR is set in frame control*/ - PACK_STRUCT_FIELD(u16_t source_pan_id); - /** Source Address is omitted if Source Addressing Mode is 0 */ - PACK_STRUCT_FLD_8(u8_t source_address[8]); - /* The rest is variable */ -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/* Addressing modes (2 bits) */ -#define IEEE_802154_ADDR_MODE_NO_ADDR 0x00 /* PAN ID and address fields are not present */ -#define IEEE_802154_ADDR_MODE_RESERVED 0x01 /* Reserved */ -#define IEEE_802154_ADDR_MODE_SHORT 0x02 /* Address field contains a short address (16 bit) */ -#define IEEE_802154_ADDR_MODE_EXT 0x03 /* Address field contains an extended address (64 bit) */ - -/* IEEE 802.15.4 Frame Control definitions (2 bytes; see IEEE 802.15.4-2015 ch. 7.2.1) */ -#define IEEE_802154_FC_FT_MASK 0x0007 /* bits 0..2: Frame Type */ -#define IEEE_802154_FC_FT_BEACON 0x00 -#define IEEE_802154_FC_FT_DATA 0x01 -#define IEEE_802154_FC_FT_ACK 0x02 -#define IEEE_802154_FC_FT_MAC_CMD 0x03 -#define IEEE_802154_FC_FT_RESERVED 0x04 -#define IEEE_802154_FC_FT_MULTIPURPOSE 0x05 -#define IEEE_802154_FC_FT_FRAG 0x06 -#define IEEE_802154_FC_FT_EXT 0x07 -#define IEEE_802154_FC_SEC_EN 0x0008 /* bit 3: Security Enabled */ -#define IEEE_802154_FC_FRAME_PEND 0x0010 /* bit 4: Frame Pending */ -#define IEEE_802154_FC_ACK_REQ 0x0020 /* bit 5: AR (ACK required) */ -#define IEEE_802154_FC_PANID_COMPR 0x0040 /* bit 6: PAN ID Compression (src and dst are equal, src PAN ID omitted) */ -#define IEEE_802154_FC_RESERVED 0x0080 -#define IEEE_802154_FC_SEQNO_SUPPR 0x0100 /* bit 8: Sequence Number Suppression */ -#define IEEE_802154_FC_IE_PRESENT 0x0200 /* bit 9: IE Present */ -#define IEEE_802154_FC_DST_ADDR_MODE_MASK 0x0c00 /* bits 10..11: Destination Addressing Mode */ -#define IEEE_802154_FC_DST_ADDR_MODE_NO_ADDR (IEEE_802154_ADDR_MODE_NO_ADDR << 10) -#define IEEE_802154_FC_DST_ADDR_MODE_SHORT (IEEE_802154_ADDR_MODE_SHORT << 10) -#define IEEE_802154_FC_DST_ADDR_MODE_EXT (IEEE_802154_ADDR_MODE_EXT << 10) -#define IEEE_802154_FC_FRAME_VERSION_MASK 0x3000 /* bits 12..13: Frame Version */ -#define IEEE_802154_FC_FRAME_VERSION_GET(x) (((x) & IEEE_802154_FC_FRAME_VERSION_MASK) >> 12) -#define IEEE_802154_FC_SRC_ADDR_MODE_MASK 0xc000 /* bits 14..15: Source Addressing Mode */ -#define IEEE_802154_FC_SRC_ADDR_MODE_SHORT (IEEE_802154_ADDR_MODE_SHORT << 14) -#define IEEE_802154_FC_SRC_ADDR_MODE_EXT (IEEE_802154_ADDR_MODE_EXT << 14) - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_NETIF_IEEE802154_H */ diff --git a/core/c/include/netif/lowpan6.h b/core/c/include/netif/lowpan6.h deleted file mode 100755 index b84b838..0000000 --- a/core/c/include/netif/lowpan6.h +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @file - * - * 6LowPAN output for IPv6. Uses ND tables for link-layer addressing. Fragments packets to 6LowPAN units. - */ - -/* - * Copyright (c) 2015 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#ifndef LWIP_HDR_LOWPAN6_H -#define LWIP_HDR_LOWPAN6_H - -#include "netif/lowpan6_opts.h" - -#if LWIP_IPV6 - -#include "netif/lowpan6_common.h" -#include "lwip/pbuf.h" -#include "lwip/ip.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** 1 second period for reassembly */ -#define LOWPAN6_TMR_INTERVAL 1000 - -void lowpan6_tmr(void); - -err_t lowpan6_set_context(u8_t idx, const ip6_addr_t * context); -err_t lowpan6_set_short_addr(u8_t addr_high, u8_t addr_low); - -#if LWIP_IPV4 -err_t lowpan4_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr); -#endif /* LWIP_IPV4 */ -err_t lowpan6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr); -err_t lowpan6_input(struct pbuf * p, struct netif *netif); -err_t lowpan6_if_init(struct netif *netif); - -/* pan_id in network byte order. */ -err_t lowpan6_set_pan_id(u16_t pan_id); - -u16_t lowpan6_calc_crc(const void *buf, u16_t len); - -#if !NO_SYS -err_t tcpip_6lowpan_input(struct pbuf *p, struct netif *inp); -#endif /* !NO_SYS */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6 */ - -#endif /* LWIP_HDR_LOWPAN6_H */ diff --git a/core/c/include/netif/lowpan6_ble.h b/core/c/include/netif/lowpan6_ble.h deleted file mode 100755 index 46a5f2e..0000000 --- a/core/c/include/netif/lowpan6_ble.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @file - * 6LowPAN over BLE for IPv6 (RFC7668). - */ - -/* - * Copyright (c) 2017 Benjamin Aigner - * Copyright (c) 2015 Inico Technologies Ltd. , Author: Ivan Delamer - * - * 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: Benjamin Aigner - * - * Based on the original 6lowpan implementation of lwIP ( @see 6lowpan.c) - */ - -#ifndef LWIP_HDR_LOWPAN6_BLE_H -#define LWIP_HDR_LOWPAN6_BLE_H - -#include "netif/lowpan6_opts.h" - -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -#include "netif/lowpan6_common.h" -#include "lwip/pbuf.h" -#include "lwip/ip.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -err_t rfc7668_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr); -err_t rfc7668_input(struct pbuf * p, struct netif *netif); -err_t rfc7668_set_local_addr_eui64(struct netif *netif, const u8_t *local_addr, size_t local_addr_len); -err_t rfc7668_set_local_addr_mac48(struct netif *netif, const u8_t *local_addr, size_t local_addr_len, int is_public_addr); -err_t rfc7668_set_peer_addr_eui64(struct netif *netif, const u8_t *peer_addr, size_t peer_addr_len); -err_t rfc7668_set_peer_addr_mac48(struct netif *netif, const u8_t *peer_addr, size_t peer_addr_len, int is_public_addr); -err_t rfc7668_set_context(u8_t index, const ip6_addr_t * context); -err_t rfc7668_if_init(struct netif *netif); - -#if !NO_SYS -err_t tcpip_rfc7668_input(struct pbuf *p, struct netif *inp); -#endif - -void ble_addr_to_eui64(uint8_t *dst, const uint8_t *src, int public_addr); -void eui64_to_ble_addr(uint8_t *dst, const uint8_t *src); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6 */ - -#endif /* LWIP_HDR_LOWPAN6_BLE_H */ diff --git a/core/c/include/netif/lowpan6_common.h b/core/c/include/netif/lowpan6_common.h deleted file mode 100755 index d80eef9..0000000 --- a/core/c/include/netif/lowpan6_common.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @file - * - * Common 6LowPAN routines for IPv6. Uses ND tables for link-layer addressing. Fragments packets to 6LowPAN units. - */ - -/* - * Copyright (c) 2015 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#ifndef LWIP_HDR_LOWPAN6_COMMON_H -#define LWIP_HDR_LOWPAN6_COMMON_H - -#include "netif/lowpan6_opts.h" - -#if LWIP_IPV6 /* don't build if IPv6 is disabled in lwipopts.h */ - -#include "lwip/pbuf.h" -#include "lwip/ip.h" -#include "lwip/ip6_addr.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Helper define for a link layer address, which can be encoded as 0, 2 or 8 bytes */ -struct lowpan6_link_addr { - /* encoded length of the address */ - u8_t addr_len; - /* address bytes */ - u8_t addr[8]; -}; - -s8_t lowpan6_get_address_mode(const ip6_addr_t *ip6addr, const struct lowpan6_link_addr *mac_addr); - -#if LWIP_6LOWPAN_IPHC -err_t lowpan6_compress_headers(struct netif *netif, u8_t *inbuf, size_t inbuf_size, u8_t *outbuf, size_t outbuf_size, - u8_t *lowpan6_header_len_out, u8_t *hidden_header_len_out, ip6_addr_t *lowpan6_contexts, - const struct lowpan6_link_addr *src, const struct lowpan6_link_addr *dst); -struct pbuf *lowpan6_decompress(struct pbuf *p, u16_t datagram_size, ip6_addr_t *lowpan6_contexts, - struct lowpan6_link_addr *src, struct lowpan6_link_addr *dest); -#endif /* LWIP_6LOWPAN_IPHC */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6 */ - -#endif /* LWIP_HDR_LOWPAN6_COMMON_H */ diff --git a/core/c/include/netif/lowpan6_opts.h b/core/c/include/netif/lowpan6_opts.h deleted file mode 100755 index 5303c15..0000000 --- a/core/c/include/netif/lowpan6_opts.h +++ /dev/null @@ -1,122 +0,0 @@ -/** - * @file - * 6LowPAN options list - */ - -/* - * Copyright (c) 2015 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#ifndef LWIP_HDR_LOWPAN6_OPTS_H -#define LWIP_HDR_LOWPAN6_OPTS_H - -#include "lwip/opt.h" - -/** LWIP_6LOWPAN_NUM_CONTEXTS: define the number of compression - * contexts per netif type - */ -#ifndef LWIP_6LOWPAN_NUM_CONTEXTS -#define LWIP_6LOWPAN_NUM_CONTEXTS 10 -#endif - -/** LWIP_6LOWPAN_INFER_SHORT_ADDRESS: set this to 0 to disable creating - * short addresses for matching addresses (debug only) - */ -#ifndef LWIP_6LOWPAN_INFER_SHORT_ADDRESS -#define LWIP_6LOWPAN_INFER_SHORT_ADDRESS 1 -#endif - -/** LWIP_6LOWPAN_IPHC: set this to 0 to disable IP header compression as per - * RFC 6282 (which is mandatory for BLE) - */ -#ifndef LWIP_6LOWPAN_IPHC -#define LWIP_6LOWPAN_IPHC 1 -#endif - -/** Set this to 1 if your IEEE 802.15.4 interface can calculate and check the - * CRC in hardware. This means TX packets get 2 zero bytes added on transmission - * which are to be filled with the CRC. - */ -#ifndef LWIP_6LOWPAN_802154_HW_CRC -#define LWIP_6LOWPAN_802154_HW_CRC 0 -#endif - -/** If LWIP_6LOWPAN_802154_HW_CRC==0, this can override the default slow - * implementation of the CRC used for 6LoWPAN over IEEE 802.15.4 (which uses - * a shift register). - */ -#ifndef LWIP_6LOWPAN_CALC_CRC -#define LWIP_6LOWPAN_CALC_CRC(buf, len) lowpan6_calc_crc(buf, len) -#endif - -/** Debug level for 6LoWPAN in general */ -#ifndef LWIP_LOWPAN6_DEBUG -#define LWIP_LOWPAN6_DEBUG LWIP_DBG_OFF -#endif - -/** Debug level for 6LoWPAN over IEEE 802.15.4 */ -#ifndef LWIP_LOWPAN6_802154_DEBUG -#define LWIP_LOWPAN6_802154_DEBUG LWIP_DBG_OFF -#endif - -/** LWIP_LOWPAN6_IP_COMPRESSED_DEBUG: enable compressed IP frame - * output debugging - */ -#ifndef LWIP_LOWPAN6_IP_COMPRESSED_DEBUG -#define LWIP_LOWPAN6_IP_COMPRESSED_DEBUG LWIP_DBG_OFF -#endif - -/** LWIP_LOWPAN6_DECOMPRESSION_DEBUG: enable decompression debug output - */ -#ifndef LWIP_LOWPAN6_DECOMPRESSION_DEBUG -#define LWIP_LOWPAN6_DECOMPRESSION_DEBUG LWIP_DBG_OFF -#endif - -/** LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG: enable decompressed IP frame - * output debugging */ -#ifndef LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG -#define LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG LWIP_DBG_OFF -#endif - -/** LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS: - * Currently, the linux kernel driver for 6lowpan sets/clears a bit in - * the address, depending on the BD address (either public or not). - * Might not be RFC7668 conform, so you may select to do that (=1) or - * not (=0) */ -#ifndef LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS -#define LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS 1 -#endif - - -#endif /* LWIP_HDR_LOWPAN6_OPTS_H */ diff --git a/core/c/include/netif/ppp/ccp.h b/core/c/include/netif/ppp/ccp.h deleted file mode 100755 index c35336f..0000000 --- a/core/c/include/netif/ppp/ccp.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * ccp.h - Definitions for PPP Compression Control Protocol. - * - * Copyright (c) 1994-2002 Paul Mackerras. 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. The name(s) of the authors of this software must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 3. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Paul Mackerras - * ". - * - * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * $Id: ccp.h,v 1.12 2004/11/04 10:02:26 paulus Exp $ - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && CCP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef CCP_H -#define CCP_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * CCP codes. - */ - -#define CCP_CONFREQ 1 -#define CCP_CONFACK 2 -#define CCP_TERMREQ 5 -#define CCP_TERMACK 6 -#define CCP_RESETREQ 14 -#define CCP_RESETACK 15 - -/* - * Max # bytes for a CCP option - */ - -#define CCP_MAX_OPTION_LENGTH 32 - -/* - * Parts of a CCP packet. - */ - -#define CCP_CODE(dp) ((dp)[0]) -#define CCP_ID(dp) ((dp)[1]) -#define CCP_LENGTH(dp) (((dp)[2] << 8) + (dp)[3]) -#define CCP_HDRLEN 4 - -#define CCP_OPT_CODE(dp) ((dp)[0]) -#define CCP_OPT_LENGTH(dp) ((dp)[1]) -#define CCP_OPT_MINLEN 2 - -#if BSDCOMPRESS_SUPPORT -/* - * Definitions for BSD-Compress. - */ - -#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */ -#define CILEN_BSD_COMPRESS 3 /* length of config. option */ - -/* Macros for handling the 3rd byte of the BSD-Compress config option. */ -#define BSD_NBITS(x) ((x) & 0x1F) /* number of bits requested */ -#define BSD_VERSION(x) ((x) >> 5) /* version of option format */ -#define BSD_CURRENT_VERSION 1 /* current version number */ -#define BSD_MAKE_OPT(v, n) (((v) << 5) | (n)) - -#define BSD_MIN_BITS 9 /* smallest code size supported */ -#define BSD_MAX_BITS 15 /* largest code size supported */ -#endif /* BSDCOMPRESS_SUPPORT */ - -#if DEFLATE_SUPPORT -/* - * Definitions for Deflate. - */ - -#define CI_DEFLATE 26 /* config option for Deflate */ -#define CI_DEFLATE_DRAFT 24 /* value used in original draft RFC */ -#define CILEN_DEFLATE 4 /* length of its config option */ - -#define DEFLATE_MIN_SIZE 9 -#define DEFLATE_MAX_SIZE 15 -#define DEFLATE_METHOD_VAL 8 -#define DEFLATE_SIZE(x) (((x) >> 4) + 8) -#define DEFLATE_METHOD(x) ((x) & 0x0F) -#define DEFLATE_MAKE_OPT(w) ((((w) - 8) << 4) + DEFLATE_METHOD_VAL) -#define DEFLATE_CHK_SEQUENCE 0 -#endif /* DEFLATE_SUPPORT */ - -#if MPPE_SUPPORT -/* - * Definitions for MPPE. - */ - -#define CI_MPPE 18 /* config option for MPPE */ -#define CILEN_MPPE 6 /* length of config option */ -#endif /* MPPE_SUPPORT */ - -#if PREDICTOR_SUPPORT -/* - * Definitions for other, as yet unsupported, compression methods. - */ - -#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */ -#define CILEN_PREDICTOR_1 2 /* length of its config option */ -#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */ -#define CILEN_PREDICTOR_2 2 /* length of its config option */ -#endif /* PREDICTOR_SUPPORT */ - -typedef struct ccp_options { -#if DEFLATE_SUPPORT - unsigned int deflate :1; /* do Deflate? */ - unsigned int deflate_correct :1; /* use correct code for deflate? */ - unsigned int deflate_draft :1; /* use draft RFC code for deflate? */ -#endif /* DEFLATE_SUPPORT */ -#if BSDCOMPRESS_SUPPORT - unsigned int bsd_compress :1; /* do BSD Compress? */ -#endif /* BSDCOMPRESS_SUPPORT */ -#if PREDICTOR_SUPPORT - unsigned int predictor_1 :1; /* do Predictor-1? */ - unsigned int predictor_2 :1; /* do Predictor-2? */ -#endif /* PREDICTOR_SUPPORT */ - -#if MPPE_SUPPORT - u8_t mppe; /* MPPE bitfield */ -#endif /* MPPE_SUPPORT */ -#if BSDCOMPRESS_SUPPORT - u_short bsd_bits; /* # bits/code for BSD Compress */ -#endif /* BSDCOMPRESS_SUPPORT */ -#if DEFLATE_SUPPORT - u_short deflate_size; /* lg(window size) for Deflate */ -#endif /* DEFLATE_SUPPORT */ - u8_t method; /* code for chosen compression method */ -} ccp_options; - -extern const struct protent ccp_protent; - -void ccp_resetrequest(ppp_pcb *pcb); /* Issue a reset-request. */ - -#ifdef __cplusplus -} -#endif - -#endif /* CCP_H */ -#endif /* PPP_SUPPORT && CCP_SUPPORT */ diff --git a/core/c/include/netif/ppp/chap-md5.h b/core/c/include/netif/ppp/chap-md5.h deleted file mode 100755 index 1f58dfe..0000000 --- a/core/c/include/netif/ppp/chap-md5.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * chap-md5.h - New CHAP/MD5 implementation. - * - * Copyright (c) 2003 Paul Mackerras. 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. The name(s) of the authors of this software must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 3. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Paul Mackerras - * ". - * - * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -extern const struct chap_digest_type md5_digest; - -#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/core/c/include/netif/ppp/chap-new.h b/core/c/include/netif/ppp/chap-new.h deleted file mode 100755 index dadd9c2..0000000 --- a/core/c/include/netif/ppp/chap-new.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * chap-new.c - New CHAP implementation. - * - * Copyright (c) 2003 Paul Mackerras. 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. The name(s) of the authors of this software must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 3. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Paul Mackerras - * ". - * - * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef CHAP_H -#define CHAP_H - -#include "ppp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * CHAP packets begin with a standard header with code, id, len (2 bytes). - */ -#define CHAP_HDRLEN 4 - -/* - * Values for the code field. - */ -#define CHAP_CHALLENGE 1 -#define CHAP_RESPONSE 2 -#define CHAP_SUCCESS 3 -#define CHAP_FAILURE 4 - -/* - * CHAP digest codes. - */ -#define CHAP_MD5 5 -#if MSCHAP_SUPPORT -#define CHAP_MICROSOFT 0x80 -#define CHAP_MICROSOFT_V2 0x81 -#endif /* MSCHAP_SUPPORT */ - -/* - * Semi-arbitrary limits on challenge and response fields. - */ -#define MAX_CHALLENGE_LEN 64 -#define MAX_RESPONSE_LEN 64 - -/* - * These limits apply to challenge and response packets we send. - * The +4 is the +1 that we actually need rounded up. - */ -#define CHAL_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_CHALLENGE_LEN + MAXNAMELEN) -#define RESP_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_RESPONSE_LEN + MAXNAMELEN) - -/* bitmask of supported algorithms */ -#if MSCHAP_SUPPORT -#define MDTYPE_MICROSOFT_V2 0x1 -#define MDTYPE_MICROSOFT 0x2 -#endif /* MSCHAP_SUPPORT */ -#define MDTYPE_MD5 0x4 -#define MDTYPE_NONE 0 - -#if MSCHAP_SUPPORT -/* Return the digest alg. ID for the most preferred digest type. */ -#define CHAP_DIGEST(mdtype) \ - ((mdtype) & MDTYPE_MD5)? CHAP_MD5: \ - ((mdtype) & MDTYPE_MICROSOFT_V2)? CHAP_MICROSOFT_V2: \ - ((mdtype) & MDTYPE_MICROSOFT)? CHAP_MICROSOFT: \ - 0 -#else /* !MSCHAP_SUPPORT */ -#define CHAP_DIGEST(mdtype) \ - ((mdtype) & MDTYPE_MD5)? CHAP_MD5: \ - 0 -#endif /* MSCHAP_SUPPORT */ - -/* Return the bit flag (lsb set) for our most preferred digest type. */ -#define CHAP_MDTYPE(mdtype) ((mdtype) ^ ((mdtype) - 1)) & (mdtype) - -/* Return the bit flag for a given digest algorithm ID. */ -#if MSCHAP_SUPPORT -#define CHAP_MDTYPE_D(digest) \ - ((digest) == CHAP_MICROSOFT_V2)? MDTYPE_MICROSOFT_V2: \ - ((digest) == CHAP_MICROSOFT)? MDTYPE_MICROSOFT: \ - ((digest) == CHAP_MD5)? MDTYPE_MD5: \ - 0 -#else /* !MSCHAP_SUPPORT */ -#define CHAP_MDTYPE_D(digest) \ - ((digest) == CHAP_MD5)? MDTYPE_MD5: \ - 0 -#endif /* MSCHAP_SUPPORT */ - -/* Can we do the requested digest? */ -#if MSCHAP_SUPPORT -#define CHAP_CANDIGEST(mdtype, digest) \ - ((digest) == CHAP_MICROSOFT_V2)? (mdtype) & MDTYPE_MICROSOFT_V2: \ - ((digest) == CHAP_MICROSOFT)? (mdtype) & MDTYPE_MICROSOFT: \ - ((digest) == CHAP_MD5)? (mdtype) & MDTYPE_MD5: \ - 0 -#else /* !MSCHAP_SUPPORT */ -#define CHAP_CANDIGEST(mdtype, digest) \ - ((digest) == CHAP_MD5)? (mdtype) & MDTYPE_MD5: \ - 0 -#endif /* MSCHAP_SUPPORT */ - -/* - * The code for each digest type has to supply one of these. - */ -struct chap_digest_type { - int code; - -#if PPP_SERVER - /* - * Note: challenge and response arguments below are formatted as - * a length byte followed by the actual challenge/response data. - */ - void (*generate_challenge)(ppp_pcb *pcb, unsigned char *challenge); - int (*verify_response)(ppp_pcb *pcb, int id, const char *name, - const unsigned char *secret, int secret_len, - const unsigned char *challenge, const unsigned char *response, - char *message, int message_space); -#endif /* PPP_SERVER */ - void (*make_response)(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name, - const unsigned char *challenge, const char *secret, int secret_len, - unsigned char *priv); - int (*check_success)(ppp_pcb *pcb, unsigned char *pkt, int len, unsigned char *priv); - void (*handle_failure)(ppp_pcb *pcb, unsigned char *pkt, int len); -}; - -/* - * Each interface is described by chap structure. - */ -#if CHAP_SUPPORT -typedef struct chap_client_state { - u8_t flags; - const char *name; - const struct chap_digest_type *digest; - unsigned char priv[64]; /* private area for digest's use */ -} chap_client_state; - -#if PPP_SERVER -typedef struct chap_server_state { - u8_t flags; - u8_t id; - const char *name; - const struct chap_digest_type *digest; - int challenge_xmits; - int challenge_pktlen; - unsigned char challenge[CHAL_MAX_PKTLEN]; -} chap_server_state; -#endif /* PPP_SERVER */ -#endif /* CHAP_SUPPORT */ - -#if 0 /* UNUSED */ -/* Hook for a plugin to validate CHAP challenge */ -extern int (*chap_verify_hook)(char *name, char *ourname, int id, - const struct chap_digest_type *digest, - unsigned char *challenge, unsigned char *response, - char *message, int message_space); -#endif /* UNUSED */ - -#if PPP_SERVER -/* Called by authentication code to start authenticating the peer. */ -extern void chap_auth_peer(ppp_pcb *pcb, const char *our_name, int digest_code); -#endif /* PPP_SERVER */ - -/* Called by auth. code to start authenticating us to the peer. */ -extern void chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code); - -/* Represents the CHAP protocol to the main pppd code */ -extern const struct protent chap_protent; - -#ifdef __cplusplus -} -#endif - -#endif /* CHAP_H */ -#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/core/c/include/netif/ppp/chap_ms.h b/core/c/include/netif/ppp/chap_ms.h deleted file mode 100755 index ed52b40..0000000 --- a/core/c/include/netif/ppp/chap_ms.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * chap_ms.h - Challenge Handshake Authentication Protocol definitions. - * - * Copyright (c) 1995 Eric Rosenquist. 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(s) of the authors of this software must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * $Id: chap_ms.h,v 1.13 2004/11/15 22:13:26 paulus Exp $ - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef CHAPMS_INCLUDE -#define CHAPMS_INCLUDE - -extern const struct chap_digest_type chapms_digest; -extern const struct chap_digest_type chapms2_digest; - -#endif /* CHAPMS_INCLUDE */ - -#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ diff --git a/core/c/include/netif/ppp/eap.h b/core/c/include/netif/ppp/eap.h deleted file mode 100755 index 61efdaf..0000000 --- a/core/c/include/netif/ppp/eap.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * eap.h - Extensible Authentication Protocol for PPP (RFC 2284) - * - * Copyright (c) 2001 by Sun Microsystems, Inc. - * All rights reserved. - * - * Non-exclusive rights to redistribute, modify, translate, and use - * this software in source and binary forms, in whole or in part, is - * hereby granted, provided that the above copyright notice is - * duplicated in any source form, and that neither the name of the - * copyright holder nor the author is used to endorse or promote - * products derived from this software. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Original version by James Carlson - * - * $Id: eap.h,v 1.2 2003/06/11 23:56:26 paulus Exp $ - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && EAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef PPP_EAP_H -#define PPP_EAP_H - -#include "ppp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Packet header = Code, id, length. - */ -#define EAP_HEADERLEN 4 - - -/* EAP message codes. */ -#define EAP_REQUEST 1 -#define EAP_RESPONSE 2 -#define EAP_SUCCESS 3 -#define EAP_FAILURE 4 - -/* EAP types */ -#define EAPT_IDENTITY 1 -#define EAPT_NOTIFICATION 2 -#define EAPT_NAK 3 /* (response only) */ -#define EAPT_MD5CHAP 4 -#define EAPT_OTP 5 /* One-Time Password; RFC 1938 */ -#define EAPT_TOKEN 6 /* Generic Token Card */ -/* 7 and 8 are unassigned. */ -#define EAPT_RSA 9 /* RSA Public Key Authentication */ -#define EAPT_DSS 10 /* DSS Unilateral */ -#define EAPT_KEA 11 /* KEA */ -#define EAPT_KEA_VALIDATE 12 /* KEA-VALIDATE */ -#define EAPT_TLS 13 /* EAP-TLS */ -#define EAPT_DEFENDER 14 /* Defender Token (AXENT) */ -#define EAPT_W2K 15 /* Windows 2000 EAP */ -#define EAPT_ARCOT 16 /* Arcot Systems */ -#define EAPT_CISCOWIRELESS 17 /* Cisco Wireless */ -#define EAPT_NOKIACARD 18 /* Nokia IP smart card */ -#define EAPT_SRP 19 /* Secure Remote Password */ -/* 20 is deprecated */ - -/* EAP SRP-SHA1 Subtypes */ -#define EAPSRP_CHALLENGE 1 /* Request 1 - Challenge */ -#define EAPSRP_CKEY 1 /* Response 1 - Client Key */ -#define EAPSRP_SKEY 2 /* Request 2 - Server Key */ -#define EAPSRP_CVALIDATOR 2 /* Response 2 - Client Validator */ -#define EAPSRP_SVALIDATOR 3 /* Request 3 - Server Validator */ -#define EAPSRP_ACK 3 /* Response 3 - final ack */ -#define EAPSRP_LWRECHALLENGE 4 /* Req/resp 4 - Lightweight rechal */ - -#define SRPVAL_EBIT 0x00000001 /* Use shared key for ECP */ - -#define SRP_PSEUDO_ID "pseudo_" -#define SRP_PSEUDO_LEN 7 - -#define MD5_SIGNATURE_SIZE 16 -#define EAP_MIN_CHALLENGE_LENGTH 17 -#define EAP_MAX_CHALLENGE_LENGTH 24 -#define EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH 3 /* 2^3-1 = 7, 17+7 = 24 */ - -#define EAP_STATES \ - "Initial", "Pending", "Closed", "Listen", "Identify", \ - "SRP1", "SRP2", "SRP3", "MD5Chall", "Open", "SRP4", "BadAuth" - -#define eap_client_active(pcb) ((pcb)->eap.es_client.ea_state == eapListen) -#if PPP_SERVER -#define eap_server_active(pcb) \ - ((pcb)->eap.es_server.ea_state >= eapIdentify && \ - (pcb)->eap.es_server.ea_state <= eapMD5Chall) -#endif /* PPP_SERVER */ - -/* - * Complete EAP state for one PPP session. - */ -enum eap_state_code { - eapInitial = 0, /* No EAP authentication yet requested */ - eapPending, /* Waiting for LCP (no timer) */ - eapClosed, /* Authentication not in use */ - eapListen, /* Client ready (and timer running) */ - eapIdentify, /* EAP Identify sent */ - eapSRP1, /* Sent EAP SRP-SHA1 Subtype 1 */ - eapSRP2, /* Sent EAP SRP-SHA1 Subtype 2 */ - eapSRP3, /* Sent EAP SRP-SHA1 Subtype 3 */ - eapMD5Chall, /* Sent MD5-Challenge */ - eapOpen, /* Completed authentication */ - eapSRP4, /* Sent EAP SRP-SHA1 Subtype 4 */ - eapBadAuth /* Failed authentication */ -}; - -struct eap_auth { - const char *ea_name; /* Our name */ - char ea_peer[MAXNAMELEN +1]; /* Peer's name */ - void *ea_session; /* Authentication library linkage */ - u_char *ea_skey; /* Shared encryption key */ - u_short ea_namelen; /* Length of our name */ - u_short ea_peerlen; /* Length of peer's name */ - enum eap_state_code ea_state; - u_char ea_id; /* Current id */ - u_char ea_requests; /* Number of Requests sent/received */ - u_char ea_responses; /* Number of Responses */ - u_char ea_type; /* One of EAPT_* */ - u32_t ea_keyflags; /* SRP shared key usage flags */ -}; - -#ifndef EAP_MAX_CHALLENGE_LENGTH -#define EAP_MAX_CHALLENGE_LENGTH 24 -#endif -typedef struct eap_state { - struct eap_auth es_client; /* Client (authenticatee) data */ -#if PPP_SERVER - struct eap_auth es_server; /* Server (authenticator) data */ -#endif /* PPP_SERVER */ - int es_savedtime; /* Saved timeout */ - int es_rechallenge; /* EAP rechallenge interval */ - int es_lwrechallenge; /* SRP lightweight rechallenge inter */ - u8_t es_usepseudo; /* Use SRP Pseudonym if offered one */ - int es_usedpseudo; /* Set if we already sent PN */ - int es_challen; /* Length of challenge string */ - u_char es_challenge[EAP_MAX_CHALLENGE_LENGTH]; -} eap_state; - -/* - * Timeouts. - */ -#if 0 /* moved to ppp_opts.h */ -#define EAP_DEFTIMEOUT 3 /* Timeout (seconds) for rexmit */ -#define EAP_DEFTRANSMITS 10 /* max # times to transmit */ -#define EAP_DEFREQTIME 20 /* Time to wait for peer request */ -#define EAP_DEFALLOWREQ 20 /* max # times to accept requests */ -#endif /* moved to ppp_opts.h */ - -void eap_authwithpeer(ppp_pcb *pcb, const char *localname); -void eap_authpeer(ppp_pcb *pcb, const char *localname); - -extern const struct protent eap_protent; - -#ifdef __cplusplus -} -#endif - -#endif /* PPP_EAP_H */ - -#endif /* PPP_SUPPORT && EAP_SUPPORT */ diff --git a/core/c/include/netif/ppp/ecp.h b/core/c/include/netif/ppp/ecp.h deleted file mode 100755 index 8be1872..0000000 --- a/core/c/include/netif/ppp/ecp.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ecp.h - Definitions for PPP Encryption Control Protocol. - * - * Copyright (c) 2002 Google, Inc. - * 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(s) of the authors of this software must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * $Id: ecp.h,v 1.2 2003/01/10 07:12:36 fcusack Exp $ - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && ECP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef ECP_H -#define ECP_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct ecp_options { - bool required; /* Is ECP required? */ - unsigned enctype; /* Encryption type */ -} ecp_options; - -extern fsm ecp_fsm[]; -extern ecp_options ecp_wantoptions[]; -extern ecp_options ecp_gotoptions[]; -extern ecp_options ecp_allowoptions[]; -extern ecp_options ecp_hisoptions[]; - -extern const struct protent ecp_protent; - -#ifdef __cplusplus -} -#endif - -#endif /* ECP_H */ -#endif /* PPP_SUPPORT && ECP_SUPPORT */ diff --git a/core/c/include/netif/ppp/eui64.h b/core/c/include/netif/ppp/eui64.h deleted file mode 100755 index ad199ea..0000000 --- a/core/c/include/netif/ppp/eui64.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * eui64.h - EUI64 routines for IPv6CP. - * - * Copyright (c) 1999 Tommi Komulainen. 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(s) of the authors of this software must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Tommi Komulainen - * ". - * - * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * $Id: eui64.h,v 1.6 2002/12/04 23:03:32 paulus Exp $ -*/ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef EUI64_H -#define EUI64_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * @todo: - * - * Maybe this should be done by processing struct in6_addr directly... - */ -typedef union -{ - u8_t e8[8]; - u16_t e16[4]; - u32_t e32[2]; -} eui64_t; - -#define eui64_iszero(e) (((e).e32[0] | (e).e32[1]) == 0) -#define eui64_equals(e, o) (((e).e32[0] == (o).e32[0]) && \ - ((e).e32[1] == (o).e32[1])) -#define eui64_zero(e) (e).e32[0] = (e).e32[1] = 0; - -#define eui64_copy(s, d) memcpy(&(d), &(s), sizeof(eui64_t)) - -#define eui64_magic(e) do { \ - (e).e32[0] = magic(); \ - (e).e32[1] = magic(); \ - (e).e8[0] &= ~2; \ - } while (0) -#define eui64_magic_nz(x) do { \ - eui64_magic(x); \ - } while (eui64_iszero(x)) -#define eui64_magic_ne(x, y) do { \ - eui64_magic(x); \ - } while (eui64_equals(x, y)) - -#define eui64_get(ll, cp) do { \ - eui64_copy((*cp), (ll)); \ - (cp) += sizeof(eui64_t); \ - } while (0) - -#define eui64_put(ll, cp) do { \ - eui64_copy((ll), (*cp)); \ - (cp) += sizeof(eui64_t); \ - } while (0) - -#define eui64_set32(e, l) do { \ - (e).e32[0] = 0; \ - (e).e32[1] = lwip_htonl(l); \ - } while (0) -#define eui64_setlo32(e, l) eui64_set32(e, l) - -char *eui64_ntoa(eui64_t); /* Returns ascii representation of id */ - -#ifdef __cplusplus -} -#endif - -#endif /* EUI64_H */ -#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/core/c/include/netif/ppp/fsm.h b/core/c/include/netif/ppp/fsm.h deleted file mode 100755 index e91536d..0000000 --- a/core/c/include/netif/ppp/fsm.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions. - * - * Copyright (c) 1984-2000 Carnegie Mellon University. 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 "Carnegie Mellon University" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For permission or any legal - * details, please contact - * Office of Technology Transfer - * Carnegie Mellon University - * 5000 Forbes Avenue - * Pittsburgh, PA 15213-3890 - * (412) 268-4387, fax: (412) 268-7395 - * tech-transfer@andrew.cmu.edu - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Computing Services - * at Carnegie Mellon University (http://www.cmu.edu/computing/)." - * - * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE - * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * $Id: fsm.h,v 1.10 2004/11/13 02:28:15 paulus Exp $ - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef FSM_H -#define FSM_H - -#include "ppp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Packet header = Code, id, length. - */ -#define HEADERLEN 4 - - -/* - * CP (LCP, IPCP, etc.) codes. - */ -#define CONFREQ 1 /* Configuration Request */ -#define CONFACK 2 /* Configuration Ack */ -#define CONFNAK 3 /* Configuration Nak */ -#define CONFREJ 4 /* Configuration Reject */ -#define TERMREQ 5 /* Termination Request */ -#define TERMACK 6 /* Termination Ack */ -#define CODEREJ 7 /* Code Reject */ - - -/* - * Each FSM is described by an fsm structure and fsm callbacks. - */ -typedef struct fsm { - ppp_pcb *pcb; /* PPP Interface */ - const struct fsm_callbacks *callbacks; /* Callback routines */ - const char *term_reason; /* Reason for closing protocol */ - u8_t seen_ack; /* Have received valid Ack/Nak/Rej to Req */ - /* -- This is our only flag, we might use u_int :1 if we have more flags */ - u16_t protocol; /* Data Link Layer Protocol field value */ - u8_t state; /* State */ - u8_t flags; /* Contains option bits */ - u8_t id; /* Current id */ - u8_t reqid; /* Current request id */ - u8_t retransmits; /* Number of retransmissions left */ - u8_t nakloops; /* Number of nak loops since last ack */ - u8_t rnakloops; /* Number of naks received */ - u8_t maxnakloops; /* Maximum number of nak loops tolerated - (necessary because IPCP require a custom large max nak loops value) */ - u8_t term_reason_len; /* Length of term_reason */ -} fsm; - - -typedef struct fsm_callbacks { - void (*resetci) /* Reset our Configuration Information */ - (fsm *); - int (*cilen) /* Length of our Configuration Information */ - (fsm *); - void (*addci) /* Add our Configuration Information */ - (fsm *, u_char *, int *); - int (*ackci) /* ACK our Configuration Information */ - (fsm *, u_char *, int); - int (*nakci) /* NAK our Configuration Information */ - (fsm *, u_char *, int, int); - int (*rejci) /* Reject our Configuration Information */ - (fsm *, u_char *, int); - int (*reqci) /* Request peer's Configuration Information */ - (fsm *, u_char *, int *, int); - void (*up) /* Called when fsm reaches PPP_FSM_OPENED state */ - (fsm *); - void (*down) /* Called when fsm leaves PPP_FSM_OPENED state */ - (fsm *); - void (*starting) /* Called when we want the lower layer */ - (fsm *); - void (*finished) /* Called when we don't want the lower layer */ - (fsm *); - void (*protreject) /* Called when Protocol-Reject received */ - (int); - void (*retransmit) /* Retransmission is necessary */ - (fsm *); - int (*extcode) /* Called when unknown code received */ - (fsm *, int, int, u_char *, int); - const char *proto_name; /* String name for protocol (for messages) */ -} fsm_callbacks; - - -/* - * Link states. - */ -#define PPP_FSM_INITIAL 0 /* Down, hasn't been opened */ -#define PPP_FSM_STARTING 1 /* Down, been opened */ -#define PPP_FSM_CLOSED 2 /* Up, hasn't been opened */ -#define PPP_FSM_STOPPED 3 /* Open, waiting for down event */ -#define PPP_FSM_CLOSING 4 /* Terminating the connection, not open */ -#define PPP_FSM_STOPPING 5 /* Terminating, but open */ -#define PPP_FSM_REQSENT 6 /* We've sent a Config Request */ -#define PPP_FSM_ACKRCVD 7 /* We've received a Config Ack */ -#define PPP_FSM_ACKSENT 8 /* We've sent a Config Ack */ -#define PPP_FSM_OPENED 9 /* Connection available */ - - -/* - * Flags - indicate options controlling FSM operation - */ -#define OPT_PASSIVE 1 /* Don't die if we don't get a response */ -#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */ -#define OPT_SILENT 4 /* Wait for peer to speak first */ - - -/* - * Timeouts. - */ -#if 0 /* moved to ppp_opts.h */ -#define DEFTIMEOUT 3 /* Timeout time in seconds */ -#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ -#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ -#define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ -#endif /* moved to ppp_opts.h */ - - -/* - * Prototypes - */ -void fsm_init(fsm *f); -void fsm_lowerup(fsm *f); -void fsm_lowerdown(fsm *f); -void fsm_open(fsm *f); -void fsm_close(fsm *f, const char *reason); -void fsm_input(fsm *f, u_char *inpacket, int l); -void fsm_protreject(fsm *f); -void fsm_sdata(fsm *f, u_char code, u_char id, const u_char *data, int datalen); - -#ifdef __cplusplus -} -#endif - -#endif /* FSM_H */ -#endif /* PPP_SUPPORT */ diff --git a/core/c/include/netif/ppp/ipcp.h b/core/c/include/netif/ppp/ipcp.h deleted file mode 100755 index 1735158..0000000 --- a/core/c/include/netif/ppp/ipcp.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * ipcp.h - IP Control Protocol definitions. - * - * Copyright (c) 1984-2000 Carnegie Mellon University. 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 "Carnegie Mellon University" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For permission or any legal - * details, please contact - * Office of Technology Transfer - * Carnegie Mellon University - * 5000 Forbes Avenue - * Pittsburgh, PA 15213-3890 - * (412) 268-4387, fax: (412) 268-7395 - * tech-transfer@andrew.cmu.edu - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Computing Services - * at Carnegie Mellon University (http://www.cmu.edu/computing/)." - * - * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE - * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * $Id: ipcp.h,v 1.14 2002/12/04 23:03:32 paulus Exp $ - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && PPP_IPV4_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef IPCP_H -#define IPCP_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Options. - */ -#define CI_ADDRS 1 /* IP Addresses */ -#if VJ_SUPPORT -#define CI_COMPRESSTYPE 2 /* Compression Type */ -#endif /* VJ_SUPPORT */ -#define CI_ADDR 3 - -#if LWIP_DNS -#define CI_MS_DNS1 129 /* Primary DNS value */ -#define CI_MS_DNS2 131 /* Secondary DNS value */ -#endif /* LWIP_DNS */ -#if 0 /* UNUSED - WINS */ -#define CI_MS_WINS1 130 /* Primary WINS value */ -#define CI_MS_WINS2 132 /* Secondary WINS value */ -#endif /* UNUSED - WINS */ - -#if VJ_SUPPORT -#define MAX_STATES 16 /* from slcompress.h */ - -#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */ -#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */ -#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */ - /* maxslot and slot number compression) */ - -#define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/ -#define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */ - /* compression option*/ -#endif /* VJ_SUPPORT */ - -typedef struct ipcp_options { - unsigned int neg_addr :1; /* Negotiate IP Address? */ - unsigned int old_addrs :1; /* Use old (IP-Addresses) option? */ - unsigned int req_addr :1; /* Ask peer to send IP address? */ -#if 0 /* UNUSED */ - unsigned int default_route :1; /* Assign default route through interface? */ - unsigned int replace_default_route :1; /* Replace default route through interface? */ -#endif /* UNUSED */ -#if 0 /* UNUSED - PROXY ARP */ - unsigned int proxy_arp :1; /* Make proxy ARP entry for peer? */ -#endif /* UNUSED - PROXY ARP */ -#if VJ_SUPPORT - unsigned int neg_vj :1; /* Van Jacobson Compression? */ - unsigned int old_vj :1; /* use old (short) form of VJ option? */ - unsigned int cflag :1; -#endif /* VJ_SUPPORT */ - unsigned int accept_local :1; /* accept peer's value for ouraddr */ - unsigned int accept_remote :1; /* accept peer's value for hisaddr */ -#if LWIP_DNS - unsigned int req_dns1 :1; /* Ask peer to send primary DNS address? */ - unsigned int req_dns2 :1; /* Ask peer to send secondary DNS address? */ -#endif /* LWIP_DNS */ - - u32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */ -#if LWIP_DNS - u32_t dnsaddr[2]; /* Primary and secondary MS DNS entries */ -#endif /* LWIP_DNS */ -#if 0 /* UNUSED - WINS */ - u32_t winsaddr[2]; /* Primary and secondary MS WINS entries */ -#endif /* UNUSED - WINS */ - -#if VJ_SUPPORT - u16_t vj_protocol; /* protocol value to use in VJ option */ - u8_t maxslotindex; /* values for RFC1332 VJ compression neg. */ -#endif /* VJ_SUPPORT */ -} ipcp_options; - -#if 0 /* UNUSED, already defined by lwIP */ -char *ip_ntoa (u32_t); -#endif /* UNUSED, already defined by lwIP */ - -extern const struct protent ipcp_protent; - -#ifdef __cplusplus -} -#endif - -#endif /* IPCP_H */ -#endif /* PPP_SUPPORT && PPP_IPV4_SUPPORT */ diff --git a/core/c/include/netif/ppp/ipv6cp.h b/core/c/include/netif/ppp/ipv6cp.h deleted file mode 100755 index 48b0715..0000000 --- a/core/c/include/netif/ppp/ipv6cp.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * ipv6cp.h - PPP IPV6 Control Protocol. - * - * Copyright (c) 1999 Tommi Komulainen. 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(s) of the authors of this software must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Tommi Komulainen - * ". - * - * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -/* Original version, based on RFC2023 : - - Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt, - Alain.Durand@imag.fr, IMAG, - Jean-Luc.Richier@imag.fr, IMAG-LSR. - - Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE, - Alain.Durand@imag.fr, IMAG, - Jean-Luc.Richier@imag.fr, IMAG-LSR. - - Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt - Économique ayant pour membres BULL S.A. et l'INRIA). - - Ce logiciel informatique est disponible aux conditions - usuelles dans la recherche, c'est-à-dire qu'il peut - être utilisé, copié, modifié, distribué à l'unique - condition que ce texte soit conservé afin que - l'origine de ce logiciel soit reconnue. - - Le nom de l'Institut National de Recherche en Informatique - et en Automatique (INRIA), de l'IMAG, ou d'une personne morale - ou physique ayant participé à l'élaboration de ce logiciel ne peut - être utilisé sans son accord préalable explicite. - - Ce logiciel est fourni tel quel sans aucune garantie, - support ou responsabilité d'aucune sorte. - Ce logiciel est dérivé de sources d'origine - "University of California at Berkeley" et - "Digital Equipment Corporation" couvertes par des copyrights. - - L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG) - est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National - Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant - sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR). - - This work has been done in the context of GIE DYADE (joint R & D venture - between BULL S.A. and INRIA). - - This software is available with usual "research" terms - with the aim of retain credits of the software. - Permission to use, copy, modify and distribute this software for any - purpose and without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies, - and the name of INRIA, IMAG, or any contributor not be used in advertising - or publicity pertaining to this material without the prior explicit - permission. The software is provided "as is" without any - warranties, support or liabilities of any kind. - This software is derived from source code from - "University of California at Berkeley" and - "Digital Equipment Corporation" protected by copyrights. - - Grenoble's Institute of Computer Science and Applied Mathematics (IMAG) - is a federation of seven research units funded by the CNRS, National - Polytechnic Institute of Grenoble and University Joseph Fourier. - The research unit in Software, Systems, Networks (LSR) is member of IMAG. -*/ - -/* - * Derived from : - * - * - * ipcp.h - IP Control Protocol definitions. - * - * Copyright (c) 1984-2000 Carnegie Mellon University. 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 "Carnegie Mellon University" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For permission or any legal - * details, please contact - * Office of Technology Transfer - * Carnegie Mellon University - * 5000 Forbes Avenue - * Pittsburgh, PA 15213-3890 - * (412) 268-4387, fax: (412) 268-7395 - * tech-transfer@andrew.cmu.edu - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Computing Services - * at Carnegie Mellon University (http://www.cmu.edu/computing/)." - * - * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE - * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * $Id: ipv6cp.h,v 1.7 2002/12/04 23:03:32 paulus Exp $ - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef IPV6CP_H -#define IPV6CP_H - -#include "eui64.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Options. - */ -#define CI_IFACEID 1 /* Interface Identifier */ -#ifdef IPV6CP_COMP -#define CI_COMPRESSTYPE 2 /* Compression Type */ -#endif /* IPV6CP_COMP */ - -/* No compression types yet defined. - *#define IPV6CP_COMP 0x004f - */ -typedef struct ipv6cp_options { - unsigned int neg_ifaceid :1; /* Negotiate interface identifier? */ - unsigned int req_ifaceid :1; /* Ask peer to send interface identifier? */ - unsigned int accept_local :1; /* accept peer's value for iface id? */ - unsigned int opt_local :1; /* ourtoken set by option */ - unsigned int opt_remote :1; /* histoken set by option */ - unsigned int use_ip :1; /* use IP as interface identifier */ -#if 0 - unsigned int use_persistent :1; /* use uniquely persistent value for address */ -#endif -#ifdef IPV6CP_COMP - unsigned int neg_vj :1; /* Van Jacobson Compression? */ -#endif /* IPV6CP_COMP */ - -#ifdef IPV6CP_COMP - u_short vj_protocol; /* protocol value to use in VJ option */ -#endif /* IPV6CP_COMP */ - eui64_t ourid, hisid; /* Interface identifiers */ -} ipv6cp_options; - -extern const struct protent ipv6cp_protent; - -#ifdef __cplusplus -} -#endif - -#endif /* IPV6CP_H */ -#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/core/c/include/netif/ppp/lcp.h b/core/c/include/netif/ppp/lcp.h deleted file mode 100755 index 37d0548..0000000 --- a/core/c/include/netif/ppp/lcp.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * lcp.h - Link Control Protocol definitions. - * - * Copyright (c) 1984-2000 Carnegie Mellon University. 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 "Carnegie Mellon University" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For permission or any legal - * details, please contact - * Office of Technology Transfer - * Carnegie Mellon University - * 5000 Forbes Avenue - * Pittsburgh, PA 15213-3890 - * (412) 268-4387, fax: (412) 268-7395 - * tech-transfer@andrew.cmu.edu - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Computing Services - * at Carnegie Mellon University (http://www.cmu.edu/computing/)." - * - * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE - * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * $Id: lcp.h,v 1.20 2004/11/14 22:53:42 carlsonj Exp $ - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef LCP_H -#define LCP_H - -#include "ppp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Options. - */ -#define CI_VENDOR 0 /* Vendor Specific */ -#define CI_MRU 1 /* Maximum Receive Unit */ -#define CI_ASYNCMAP 2 /* Async Control Character Map */ -#define CI_AUTHTYPE 3 /* Authentication Type */ -#define CI_QUALITY 4 /* Quality Protocol */ -#define CI_MAGICNUMBER 5 /* Magic Number */ -#define CI_PCOMPRESSION 7 /* Protocol Field Compression */ -#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */ -#define CI_FCSALTERN 9 /* FCS-Alternatives */ -#define CI_SDP 10 /* Self-Describing-Pad */ -#define CI_NUMBERED 11 /* Numbered-Mode */ -#define CI_CALLBACK 13 /* callback */ -#define CI_MRRU 17 /* max reconstructed receive unit; multilink */ -#define CI_SSNHF 18 /* short sequence numbers for multilink */ -#define CI_EPDISC 19 /* endpoint discriminator */ -#define CI_MPPLUS 22 /* Multi-Link-Plus-Procedure */ -#define CI_LDISC 23 /* Link-Discriminator */ -#define CI_LCPAUTH 24 /* LCP Authentication */ -#define CI_COBS 25 /* Consistent Overhead Byte Stuffing */ -#define CI_PREFELIS 26 /* Prefix Elision */ -#define CI_MPHDRFMT 27 /* MP Header Format */ -#define CI_I18N 28 /* Internationalization */ -#define CI_SDL 29 /* Simple Data Link */ - -/* - * LCP-specific packet types (code numbers). - */ -#define PROTREJ 8 /* Protocol Reject */ -#define ECHOREQ 9 /* Echo Request */ -#define ECHOREP 10 /* Echo Reply */ -#define DISCREQ 11 /* Discard Request */ -#define IDENTIF 12 /* Identification */ -#define TIMEREM 13 /* Time Remaining */ - -/* Value used as data for CI_CALLBACK option */ -#define CBCP_OPT 6 /* Use callback control protocol */ - -#if 0 /* moved to ppp_opts.h */ -#define DEFMRU 1500 /* Try for this */ -#define MINMRU 128 /* No MRUs below this */ -#define MAXMRU 16384 /* Normally limit MRU to this */ -#endif /* moved to ppp_opts.h */ - -/* An endpoint discriminator, used with multilink. */ -#define MAX_ENDP_LEN 20 /* maximum length of discriminator value */ -struct epdisc { - unsigned char class_; /* -- The word "class" is reserved in C++. */ - unsigned char length; - unsigned char value[MAX_ENDP_LEN]; -}; - -/* - * The state of options is described by an lcp_options structure. - */ -typedef struct lcp_options { - unsigned int passive :1; /* Don't die if we don't get a response */ - unsigned int silent :1; /* Wait for the other end to start first */ -#if 0 /* UNUSED */ - unsigned int restart :1; /* Restart vs. exit after close */ -#endif /* UNUSED */ - unsigned int neg_mru :1; /* Negotiate the MRU? */ - unsigned int neg_asyncmap :1; /* Negotiate the async map? */ -#if PAP_SUPPORT - unsigned int neg_upap :1; /* Ask for UPAP authentication? */ -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - unsigned int neg_chap :1; /* Ask for CHAP authentication? */ -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT - unsigned int neg_eap :1; /* Ask for EAP authentication? */ -#endif /* EAP_SUPPORT */ - unsigned int neg_magicnumber :1; /* Ask for magic number? */ - unsigned int neg_pcompression :1; /* HDLC Protocol Field Compression? */ - unsigned int neg_accompression :1; /* HDLC Address/Control Field Compression? */ -#if LQR_SUPPORT - unsigned int neg_lqr :1; /* Negotiate use of Link Quality Reports */ -#endif /* LQR_SUPPORT */ - unsigned int neg_cbcp :1; /* Negotiate use of CBCP */ -#ifdef HAVE_MULTILINK - unsigned int neg_mrru :1; /* negotiate multilink MRRU */ -#endif /* HAVE_MULTILINK */ - unsigned int neg_ssnhf :1; /* negotiate short sequence numbers */ - unsigned int neg_endpoint :1; /* negotiate endpoint discriminator */ - - u16_t mru; /* Value of MRU */ -#ifdef HAVE_MULTILINK - u16_t mrru; /* Value of MRRU, and multilink enable */ -#endif /* MULTILINK */ -#if CHAP_SUPPORT - u8_t chap_mdtype; /* which MD types (hashing algorithm) */ -#endif /* CHAP_SUPPORT */ - u32_t asyncmap; /* Value of async map */ - u32_t magicnumber; - u8_t numloops; /* Number of loops during magic number neg. */ -#if LQR_SUPPORT - u32_t lqr_period; /* Reporting period for LQR 1/100ths second */ -#endif /* LQR_SUPPORT */ - struct epdisc endpoint; /* endpoint discriminator */ -} lcp_options; - -void lcp_open(ppp_pcb *pcb); -void lcp_close(ppp_pcb *pcb, const char *reason); -void lcp_lowerup(ppp_pcb *pcb); -void lcp_lowerdown(ppp_pcb *pcb); -void lcp_sprotrej(ppp_pcb *pcb, u_char *p, int len); /* send protocol reject */ - -extern const struct protent lcp_protent; - -#if 0 /* moved to ppp_opts.h */ -/* Default number of times we receive our magic number from the peer - before deciding the link is looped-back. */ -#define DEFLOOPBACKFAIL 10 -#endif /* moved to ppp_opts.h */ - -#ifdef __cplusplus -} -#endif - -#endif /* LCP_H */ -#endif /* PPP_SUPPORT */ diff --git a/core/c/include/netif/ppp/magic.h b/core/c/include/netif/ppp/magic.h deleted file mode 100755 index ffbd073..0000000 --- a/core/c/include/netif/ppp/magic.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * magic.h - PPP Magic Number definitions. - * - * Copyright (c) 1984-2000 Carnegie Mellon University. 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 "Carnegie Mellon University" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For permission or any legal - * details, please contact - * Office of Technology Transfer - * Carnegie Mellon University - * 5000 Forbes Avenue - * Pittsburgh, PA 15213-3890 - * (412) 268-4387, fax: (412) 268-7395 - * tech-transfer@andrew.cmu.edu - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Computing Services - * at Carnegie Mellon University (http://www.cmu.edu/computing/)." - * - * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE - * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * $Id: magic.h,v 1.5 2003/06/11 23:56:26 paulus Exp $ - */ -/***************************************************************************** -* randm.h - Random number generator header file. -* -* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. -* Copyright (c) 1998 Global Election Systems 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 -* -* 03-01-01 Marc Boucher -* Ported to lwIP. -* 98-05-29 Guy Lancaster , Global Election Systems Inc. -* Extracted from avos. -*****************************************************************************/ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef MAGIC_H -#define MAGIC_H - -#ifdef __cplusplus -extern "C" { -#endif - -/*********************** -*** PUBLIC FUNCTIONS *** -***********************/ - -/* - * Initialize the random number generator. - */ -void magic_init(void); - -/* - * Randomize our random seed value. To be called for truely random events - * such as user operations and network traffic. - */ -void magic_randomize(void); - -/* - * Return a new random number. - */ -u32_t magic(void); /* Returns the next magic number */ - -/* - * Fill buffer with random bytes - * - * Use the random pool to generate random data. This degrades to pseudo - * random when used faster than randomness is supplied using magic_churnrand(). - * Thus it's important to make sure that the results of this are not - * published directly because one could predict the next result to at - * least some degree. Also, it's important to get a good seed before - * the first use. - */ -void magic_random_bytes(unsigned char *buf, u32_t buf_len); - -/* - * Return a new random number between 0 and (2^pow)-1 included. - */ -u32_t magic_pow(u8_t pow); - -#ifdef __cplusplus -} -#endif - -#endif /* MAGIC_H */ - -#endif /* PPP_SUPPORT */ diff --git a/core/c/include/netif/ppp/mppe.h b/core/c/include/netif/ppp/mppe.h deleted file mode 100755 index 4f504fb..0000000 --- a/core/c/include/netif/ppp/mppe.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * mppe.h - Definitions for MPPE - * - * Copyright (c) 2008 Paul Mackerras. 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(s) of the authors of this software must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Paul Mackerras - * ". - * - * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && MPPE_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef MPPE_H -#define MPPE_H - -#include "netif/ppp/pppcrypt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define MPPE_PAD 4 /* MPPE growth per frame */ -#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */ - -/* option bits for ccp_options.mppe */ -#define MPPE_OPT_40 0x01 /* 40 bit */ -#define MPPE_OPT_128 0x02 /* 128 bit */ -#define MPPE_OPT_STATEFUL 0x04 /* stateful mode */ -/* unsupported opts */ -#define MPPE_OPT_56 0x08 /* 56 bit */ -#define MPPE_OPT_MPPC 0x10 /* MPPC compression */ -#define MPPE_OPT_D 0x20 /* Unknown */ -#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D) -#define MPPE_OPT_UNKNOWN 0x40 /* Bits !defined in RFC 3078 were set */ - -/* - * This is not nice ... the alternative is a bitfield struct though. - * And unfortunately, we cannot share the same bits for the option - * names above since C and H are the same bit. We could do a u_int32 - * but then we have to do a lwip_htonl() all the time and/or we still need - * to know which octet is which. - */ -#define MPPE_C_BIT 0x01 /* MPPC */ -#define MPPE_D_BIT 0x10 /* Obsolete, usage unknown */ -#define MPPE_L_BIT 0x20 /* 40-bit */ -#define MPPE_S_BIT 0x40 /* 128-bit */ -#define MPPE_M_BIT 0x80 /* 56-bit, not supported */ -#define MPPE_H_BIT 0x01 /* Stateless (in a different byte) */ - -/* Does not include H bit; used for least significant octet only. */ -#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT) - -/* Build a CI from mppe opts (see RFC 3078) */ -#define MPPE_OPTS_TO_CI(opts, ci) \ - do { \ - u_char *ptr = ci; /* u_char[4] */ \ - \ - /* H bit */ \ - if (opts & MPPE_OPT_STATEFUL) \ - *ptr++ = 0x0; \ - else \ - *ptr++ = MPPE_H_BIT; \ - *ptr++ = 0; \ - *ptr++ = 0; \ - \ - /* S,L bits */ \ - *ptr = 0; \ - if (opts & MPPE_OPT_128) \ - *ptr |= MPPE_S_BIT; \ - if (opts & MPPE_OPT_40) \ - *ptr |= MPPE_L_BIT; \ - /* M,D,C bits not supported */ \ - } while (/* CONSTCOND */ 0) - -/* The reverse of the above */ -#define MPPE_CI_TO_OPTS(ci, opts) \ - do { \ - const u_char *ptr = ci; /* u_char[4] */ \ - \ - opts = 0; \ - \ - /* H bit */ \ - if (!(ptr[0] & MPPE_H_BIT)) \ - opts |= MPPE_OPT_STATEFUL; \ - \ - /* S,L bits */ \ - if (ptr[3] & MPPE_S_BIT) \ - opts |= MPPE_OPT_128; \ - if (ptr[3] & MPPE_L_BIT) \ - opts |= MPPE_OPT_40; \ - \ - /* M,D,C bits */ \ - if (ptr[3] & MPPE_M_BIT) \ - opts |= MPPE_OPT_56; \ - if (ptr[3] & MPPE_D_BIT) \ - opts |= MPPE_OPT_D; \ - if (ptr[3] & MPPE_C_BIT) \ - opts |= MPPE_OPT_MPPC; \ - \ - /* Other bits */ \ - if (ptr[0] & ~MPPE_H_BIT) \ - opts |= MPPE_OPT_UNKNOWN; \ - if (ptr[1] || ptr[2]) \ - opts |= MPPE_OPT_UNKNOWN; \ - if (ptr[3] & ~MPPE_ALL_BITS) \ - opts |= MPPE_OPT_UNKNOWN; \ - } while (/* CONSTCOND */ 0) - -/* Shared MPPE padding between MSCHAP and MPPE */ -#define SHA1_PAD_SIZE 40 - -static const u8_t mppe_sha1_pad1[SHA1_PAD_SIZE] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static const u8_t mppe_sha1_pad2[SHA1_PAD_SIZE] = { - 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, - 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, - 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, - 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 -}; - -/* - * State for an MPPE (de)compressor. - */ -typedef struct ppp_mppe_state { - lwip_arc4_context arc4; - u8_t master_key[MPPE_MAX_KEY_LEN]; - u8_t session_key[MPPE_MAX_KEY_LEN]; - u8_t keylen; /* key length in bytes */ - /* NB: 128-bit == 16, 40-bit == 8! - * If we want to support 56-bit, the unit has to change to bits - */ - u8_t bits; /* MPPE control bits */ - u16_t ccount; /* 12-bit coherency count (seqno) */ - u16_t sanity_errors; /* take down LCP if too many */ - unsigned int stateful :1; /* stateful mode flag */ - unsigned int discard :1; /* stateful mode packet loss flag */ -} ppp_mppe_state; - -void mppe_set_key(ppp_pcb *pcb, ppp_mppe_state *state, u8_t *key); -void mppe_init(ppp_pcb *pcb, ppp_mppe_state *state, u8_t options); -void mppe_comp_reset(ppp_pcb *pcb, ppp_mppe_state *state); -err_t mppe_compress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb, u16_t protocol); -void mppe_decomp_reset(ppp_pcb *pcb, ppp_mppe_state *state); -err_t mppe_decompress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb); - -#ifdef __cplusplus -} -#endif - -#endif /* MPPE_H */ -#endif /* PPP_SUPPORT && MPPE_SUPPORT */ diff --git a/core/c/include/netif/ppp/polarssl/arc4.h b/core/c/include/netif/ppp/polarssl/arc4.h deleted file mode 100755 index 863626d..0000000 --- a/core/c/include/netif/ppp/polarssl/arc4.h +++ /dev/null @@ -1,81 +0,0 @@ -/** - * \file arc4.h - * - * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine - * - * Copyright (C) 2009 Paul Bakker - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the names of PolarSSL or XySSL 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 COPYRIGHT HOLDERS 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 COPYRIGHT - * OWNER 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. - */ - -#include "netif/ppp/ppp_opts.h" -#if LWIP_INCLUDED_POLARSSL_ARC4 - -#ifndef LWIP_INCLUDED_POLARSSL_ARC4_H -#define LWIP_INCLUDED_POLARSSL_ARC4_H - -/** - * \brief ARC4 context structure - */ -typedef struct -{ - int x; /*!< permutation index */ - int y; /*!< permutation index */ - unsigned char m[256]; /*!< permutation table */ -} -arc4_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief ARC4 key schedule - * - * \param ctx ARC4 context to be initialized - * \param key the secret key - * \param keylen length of the key - */ -void arc4_setup( arc4_context *ctx, unsigned char *key, int keylen ); - -/** - * \brief ARC4 cipher function - * - * \param ctx ARC4 context - * \param buf buffer to be processed - * \param buflen amount of data in buf - */ -void arc4_crypt( arc4_context *ctx, unsigned char *buf, int buflen ); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_INCLUDED_POLARSSL_ARC4_H */ - -#endif /* LWIP_INCLUDED_POLARSSL_ARC4 */ diff --git a/core/c/include/netif/ppp/polarssl/des.h b/core/c/include/netif/ppp/polarssl/des.h deleted file mode 100755 index ad2f0a2..0000000 --- a/core/c/include/netif/ppp/polarssl/des.h +++ /dev/null @@ -1,92 +0,0 @@ -/** - * \file des.h - * - * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine - * - * Copyright (C) 2009 Paul Bakker - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the names of PolarSSL or XySSL 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 COPYRIGHT HOLDERS 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 COPYRIGHT - * OWNER 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. - */ - -#include "netif/ppp/ppp_opts.h" -#if LWIP_INCLUDED_POLARSSL_DES - -#ifndef LWIP_INCLUDED_POLARSSL_DES_H -#define LWIP_INCLUDED_POLARSSL_DES_H - -#define DES_ENCRYPT 1 -#define DES_DECRYPT 0 - -/** - * \brief DES context structure - */ -typedef struct -{ - int mode; /*!< encrypt/decrypt */ - unsigned long sk[32]; /*!< DES subkeys */ -} -des_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief DES key schedule (56-bit, encryption) - * - * \param ctx DES context to be initialized - * \param key 8-byte secret key - */ -void des_setkey_enc( des_context *ctx, unsigned char key[8] ); - -/** - * \brief DES key schedule (56-bit, decryption) - * - * \param ctx DES context to be initialized - * \param key 8-byte secret key - */ -void des_setkey_dec( des_context *ctx, unsigned char key[8] ); - -/** - * \brief DES-ECB block encryption/decryption - * - * \param ctx DES context - * \param input 64-bit input block - * \param output 64-bit output block - */ -void des_crypt_ecb( des_context *ctx, - const unsigned char input[8], - unsigned char output[8] ); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_INCLUDED_POLARSSL_DES_H */ - -#endif /* LWIP_INCLUDED_POLARSSL_DES */ diff --git a/core/c/include/netif/ppp/polarssl/md4.h b/core/c/include/netif/ppp/polarssl/md4.h deleted file mode 100755 index 2262995..0000000 --- a/core/c/include/netif/ppp/polarssl/md4.h +++ /dev/null @@ -1,97 +0,0 @@ -/** - * \file md4.h - * - * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine - * - * Copyright (C) 2009 Paul Bakker - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the names of PolarSSL or XySSL 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 COPYRIGHT HOLDERS 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 COPYRIGHT - * OWNER 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. - */ - -#include "netif/ppp/ppp_opts.h" -#if LWIP_INCLUDED_POLARSSL_MD4 - -#ifndef LWIP_INCLUDED_POLARSSL_MD4_H -#define LWIP_INCLUDED_POLARSSL_MD4_H - -/** - * \brief MD4 context structure - */ -typedef struct -{ - unsigned long total[2]; /*!< number of bytes processed */ - unsigned long state[4]; /*!< intermediate digest state */ - unsigned char buffer[64]; /*!< data block being processed */ -} -md4_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief MD4 context setup - * - * \param ctx context to be initialized - */ -void md4_starts( md4_context *ctx ); - -/** - * \brief MD4 process buffer - * - * \param ctx MD4 context - * \param input buffer holding the data - * \param ilen length of the input data - */ -void md4_update( md4_context *ctx, const unsigned char *input, int ilen ); - -/** - * \brief MD4 final digest - * - * \param ctx MD4 context - * \param output MD4 checksum result - */ -void md4_finish( md4_context *ctx, unsigned char output[16] ); - -/** - * \brief Output = MD4( input buffer ) - * - * \param input buffer holding the data - * \param ilen length of the input data - * \param output MD4 checksum result - */ -void md4( unsigned char *input, int ilen, unsigned char output[16] ); - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_INCLUDED_POLARSSL_MD4_H */ - -#endif /* LWIP_INCLUDED_POLARSSL_MD4 */ diff --git a/core/c/include/netif/ppp/polarssl/md5.h b/core/c/include/netif/ppp/polarssl/md5.h deleted file mode 100755 index 3059e1d..0000000 --- a/core/c/include/netif/ppp/polarssl/md5.h +++ /dev/null @@ -1,96 +0,0 @@ -/** - * \file md5.h - * - * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine - * - * Copyright (C) 2009 Paul Bakker - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the names of PolarSSL or XySSL 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 COPYRIGHT HOLDERS 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 COPYRIGHT - * OWNER 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. - */ - -#include "netif/ppp/ppp_opts.h" -#if LWIP_INCLUDED_POLARSSL_MD5 - -#ifndef LWIP_INCLUDED_POLARSSL_MD5_H -#define LWIP_INCLUDED_POLARSSL_MD5_H - -/** - * \brief MD5 context structure - */ -typedef struct -{ - unsigned long total[2]; /*!< number of bytes processed */ - unsigned long state[4]; /*!< intermediate digest state */ - unsigned char buffer[64]; /*!< data block being processed */ -} -md5_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief MD5 context setup - * - * \param ctx context to be initialized - */ -void md5_starts( md5_context *ctx ); - -/** - * \brief MD5 process buffer - * - * \param ctx MD5 context - * \param input buffer holding the data - * \param ilen length of the input data - */ -void md5_update( md5_context *ctx, const unsigned char *input, int ilen ); - -/** - * \brief MD5 final digest - * - * \param ctx MD5 context - * \param output MD5 checksum result - */ -void md5_finish( md5_context *ctx, unsigned char output[16] ); - -/** - * \brief Output = MD5( input buffer ) - * - * \param input buffer holding the data - * \param ilen length of the input data - * \param output MD5 checksum result - */ -void md5( unsigned char *input, int ilen, unsigned char output[16] ); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_INCLUDED_POLARSSL_MD5_H */ - -#endif /* LWIP_INCLUDED_POLARSSL_MD5 */ diff --git a/core/c/include/netif/ppp/polarssl/sha1.h b/core/c/include/netif/ppp/polarssl/sha1.h deleted file mode 100755 index 6d2a76e..0000000 --- a/core/c/include/netif/ppp/polarssl/sha1.h +++ /dev/null @@ -1,96 +0,0 @@ -/** - * \file sha1.h - * - * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine - * - * Copyright (C) 2009 Paul Bakker - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the names of PolarSSL or XySSL 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 COPYRIGHT HOLDERS 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 COPYRIGHT - * OWNER 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. - */ - -#include "netif/ppp/ppp_opts.h" -#if LWIP_INCLUDED_POLARSSL_SHA1 - -#ifndef LWIP_INCLUDED_POLARSSL_SHA1_H -#define LWIP_INCLUDED_POLARSSL_SHA1_H - -/** - * \brief SHA-1 context structure - */ -typedef struct -{ - unsigned long total[2]; /*!< number of bytes processed */ - unsigned long state[5]; /*!< intermediate digest state */ - unsigned char buffer[64]; /*!< data block being processed */ -} -sha1_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief SHA-1 context setup - * - * \param ctx context to be initialized - */ -void sha1_starts( sha1_context *ctx ); - -/** - * \brief SHA-1 process buffer - * - * \param ctx SHA-1 context - * \param input buffer holding the data - * \param ilen length of the input data - */ -void sha1_update( sha1_context *ctx, const unsigned char *input, int ilen ); - -/** - * \brief SHA-1 final digest - * - * \param ctx SHA-1 context - * \param output SHA-1 checksum result - */ -void sha1_finish( sha1_context *ctx, unsigned char output[20] ); - -/** - * \brief Output = SHA-1( input buffer ) - * - * \param input buffer holding the data - * \param ilen length of the input data - * \param output SHA-1 checksum result - */ -void sha1( unsigned char *input, int ilen, unsigned char output[20] ); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_INCLUDED_POLARSSL_SHA1_H */ - -#endif /* LWIP_INCLUDED_POLARSSL_SHA1 */ diff --git a/core/c/include/netif/ppp/ppp.h b/core/c/include/netif/ppp/ppp.h deleted file mode 100755 index 3595b7b..0000000 --- a/core/c/include/netif/ppp/ppp.h +++ /dev/null @@ -1,698 +0,0 @@ -/***************************************************************************** -* ppp.h - Network Point to Point Protocol header file. -* -* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. -* portions Copyright (c) 1997 Global Election Systems 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 -* -* 03-01-01 Marc Boucher -* Ported to lwIP. -* 97-11-05 Guy Lancaster , Global Election Systems Inc. -* Original derived from BSD codes. -*****************************************************************************/ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef PPP_H -#define PPP_H - -#include "lwip/def.h" -#include "lwip/stats.h" -#include "lwip/mem.h" -#include "lwip/netif.h" -#include "lwip/sys.h" -#include "lwip/timeouts.h" -#if PPP_IPV6_SUPPORT -#include "lwip/ip6_addr.h" -#endif /* PPP_IPV6_SUPPORT */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Disable non-working or rarely used PPP feature, so rarely that we don't want to bloat ppp_opts.h with them */ -#ifndef PPP_OPTIONS -#define PPP_OPTIONS 0 -#endif - -#ifndef PPP_NOTIFY -#define PPP_NOTIFY 0 -#endif - -#ifndef PPP_REMOTENAME -#define PPP_REMOTENAME 0 -#endif - -#ifndef PPP_IDLETIMELIMIT -#define PPP_IDLETIMELIMIT 0 -#endif - -#ifndef PPP_LCP_ADAPTIVE -#define PPP_LCP_ADAPTIVE 0 -#endif - -#ifndef PPP_MAXCONNECT -#define PPP_MAXCONNECT 0 -#endif - -#ifndef PPP_ALLOWED_ADDRS -#define PPP_ALLOWED_ADDRS 0 -#endif - -#ifndef PPP_PROTOCOLNAME -#define PPP_PROTOCOLNAME 0 -#endif - -#ifndef PPP_STATS_SUPPORT -#define PPP_STATS_SUPPORT 0 -#endif - -#ifndef DEFLATE_SUPPORT -#define DEFLATE_SUPPORT 0 -#endif - -#ifndef BSDCOMPRESS_SUPPORT -#define BSDCOMPRESS_SUPPORT 0 -#endif - -#ifndef PREDICTOR_SUPPORT -#define PREDICTOR_SUPPORT 0 -#endif - -/************************* -*** PUBLIC DEFINITIONS *** -*************************/ - -/* - * The basic PPP frame. - */ -#define PPP_HDRLEN 4 /* octets for standard ppp header */ -#define PPP_FCSLEN 2 /* octets for FCS */ - -/* - * Values for phase. - */ -#define PPP_PHASE_DEAD 0 -#define PPP_PHASE_MASTER 1 -#define PPP_PHASE_HOLDOFF 2 -#define PPP_PHASE_INITIALIZE 3 -#define PPP_PHASE_SERIALCONN 4 -#define PPP_PHASE_DORMANT 5 -#define PPP_PHASE_ESTABLISH 6 -#define PPP_PHASE_AUTHENTICATE 7 -#define PPP_PHASE_CALLBACK 8 -#define PPP_PHASE_NETWORK 9 -#define PPP_PHASE_RUNNING 10 -#define PPP_PHASE_TERMINATE 11 -#define PPP_PHASE_DISCONNECT 12 - -/* Error codes. */ -#define PPPERR_NONE 0 /* No error. */ -#define PPPERR_PARAM 1 /* Invalid parameter. */ -#define PPPERR_OPEN 2 /* Unable to open PPP session. */ -#define PPPERR_DEVICE 3 /* Invalid I/O device for PPP. */ -#define PPPERR_ALLOC 4 /* Unable to allocate resources. */ -#define PPPERR_USER 5 /* User interrupt. */ -#define PPPERR_CONNECT 6 /* Connection lost. */ -#define PPPERR_AUTHFAIL 7 /* Failed authentication challenge. */ -#define PPPERR_PROTOCOL 8 /* Failed to meet protocol. */ -#define PPPERR_PEERDEAD 9 /* Connection timeout */ -#define PPPERR_IDLETIMEOUT 10 /* Idle Timeout */ -#define PPPERR_CONNECTTIME 11 /* Max connect time reached */ -#define PPPERR_LOOPBACK 12 /* Loopback detected */ - -/* Whether auth support is enabled at all */ -#define PPP_AUTH_SUPPORT (PAP_SUPPORT || CHAP_SUPPORT || EAP_SUPPORT) - -/************************ -*** PUBLIC DATA TYPES *** -************************/ - -/* - * Other headers require ppp_pcb definition for prototypes, but ppp_pcb - * require some structure definition from other headers as well, we are - * fixing the dependency loop here by declaring the ppp_pcb type then - * by including headers containing necessary struct definition for ppp_pcb - */ -typedef struct ppp_pcb_s ppp_pcb; - -/* Type definitions for BSD code. */ -#ifndef __u_char_defined -typedef unsigned long u_long; -typedef unsigned int u_int; -typedef unsigned short u_short; -typedef unsigned char u_char; -#endif - -#include "fsm.h" -#include "lcp.h" -#if CCP_SUPPORT -#include "ccp.h" -#endif /* CCP_SUPPORT */ -#if MPPE_SUPPORT -#include "mppe.h" -#endif /* MPPE_SUPPORT */ -#if PPP_IPV4_SUPPORT -#include "ipcp.h" -#endif /* PPP_IPV4_SUPPORT */ -#if PPP_IPV6_SUPPORT -#include "ipv6cp.h" -#endif /* PPP_IPV6_SUPPORT */ -#if PAP_SUPPORT -#include "upap.h" -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT -#include "chap-new.h" -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT -#include "eap.h" -#endif /* EAP_SUPPORT */ -#if VJ_SUPPORT -#include "vj.h" -#endif /* VJ_SUPPORT */ - -/* Link status callback function prototype */ -typedef void (*ppp_link_status_cb_fn)(ppp_pcb *pcb, int err_code, void *ctx); - -/* - * PPP configuration. - */ -typedef struct ppp_settings_s { - -#if PPP_SERVER && PPP_AUTH_SUPPORT - unsigned int auth_required :1; /* Peer is required to authenticate */ - unsigned int null_login :1; /* Username of "" and a password of "" are acceptable */ -#endif /* PPP_SERVER && PPP_AUTH_SUPPORT */ -#if PPP_REMOTENAME - unsigned int explicit_remote :1; /* remote_name specified with remotename opt */ -#endif /* PPP_REMOTENAME */ -#if PAP_SUPPORT - unsigned int refuse_pap :1; /* Don't proceed auth. with PAP */ -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT - unsigned int refuse_chap :1; /* Don't proceed auth. with CHAP */ -#endif /* CHAP_SUPPORT */ -#if MSCHAP_SUPPORT - unsigned int refuse_mschap :1; /* Don't proceed auth. with MS-CHAP */ - unsigned int refuse_mschap_v2 :1; /* Don't proceed auth. with MS-CHAPv2 */ -#endif /* MSCHAP_SUPPORT */ -#if EAP_SUPPORT - unsigned int refuse_eap :1; /* Don't proceed auth. with EAP */ -#endif /* EAP_SUPPORT */ -#if LWIP_DNS - unsigned int usepeerdns :1; /* Ask peer for DNS adds */ -#endif /* LWIP_DNS */ - unsigned int persist :1; /* Persist mode, always try to open the connection */ -#if PRINTPKT_SUPPORT - unsigned int hide_password :1; /* Hide password in dumped packets */ -#endif /* PRINTPKT_SUPPORT */ - unsigned int noremoteip :1; /* Let him have no IP address */ - unsigned int lax_recv :1; /* accept control chars in asyncmap */ - unsigned int noendpoint :1; /* don't send/accept endpoint discriminator */ -#if PPP_LCP_ADAPTIVE - unsigned int lcp_echo_adaptive :1; /* request echo only if the link was idle */ -#endif /* PPP_LCP_ADAPTIVE */ -#if MPPE_SUPPORT - unsigned int require_mppe :1; /* Require MPPE (Microsoft Point to Point Encryption) */ - unsigned int refuse_mppe_40 :1; /* Allow MPPE 40-bit mode? */ - unsigned int refuse_mppe_128 :1; /* Allow MPPE 128-bit mode? */ - unsigned int refuse_mppe_stateful :1; /* Allow MPPE stateful mode? */ -#endif /* MPPE_SUPPORT */ - - u16_t listen_time; /* time to listen first (ms), waiting for peer to send LCP packet */ - -#if PPP_IDLETIMELIMIT - u16_t idle_time_limit; /* Disconnect if idle for this many seconds */ -#endif /* PPP_IDLETIMELIMIT */ -#if PPP_MAXCONNECT - u32_t maxconnect; /* Maximum connect time (seconds) */ -#endif /* PPP_MAXCONNECT */ - -#if PPP_AUTH_SUPPORT - /* auth data */ - const char *user; /* Username for PAP */ - const char *passwd; /* Password for PAP, secret for CHAP */ -#if PPP_REMOTENAME - char remote_name[MAXNAMELEN + 1]; /* Peer's name for authentication */ -#endif /* PPP_REMOTENAME */ - -#if PAP_SUPPORT - u8_t pap_timeout_time; /* Timeout (seconds) for auth-req retrans. */ - u8_t pap_max_transmits; /* Number of auth-reqs sent */ -#if PPP_SERVER - u8_t pap_req_timeout; /* Time to wait for auth-req from peer */ -#endif /* PPP_SERVER */ -#endif /* PAP_SUPPPORT */ - -#if CHAP_SUPPORT - u8_t chap_timeout_time; /* Timeout (seconds) for retransmitting req */ - u8_t chap_max_transmits; /* max # times to send challenge */ -#if PPP_SERVER - u8_t chap_rechallenge_time; /* Time to wait for auth-req from peer */ -#endif /* PPP_SERVER */ -#endif /* CHAP_SUPPPORT */ - -#if EAP_SUPPORT - u8_t eap_req_time; /* Time to wait (for retransmit/fail) */ - u8_t eap_allow_req; /* Max Requests allowed */ -#if PPP_SERVER - u8_t eap_timeout_time; /* Time to wait (for retransmit/fail) */ - u8_t eap_max_transmits; /* Max Requests allowed */ -#endif /* PPP_SERVER */ -#endif /* EAP_SUPPORT */ - -#endif /* PPP_AUTH_SUPPORT */ - - u8_t fsm_timeout_time; /* Timeout time in seconds */ - u8_t fsm_max_conf_req_transmits; /* Maximum Configure-Request transmissions */ - u8_t fsm_max_term_transmits; /* Maximum Terminate-Request transmissions */ - u8_t fsm_max_nak_loops; /* Maximum number of nak loops tolerated */ - - u8_t lcp_loopbackfail; /* Number of times we receive our magic number from the peer - before deciding the link is looped-back. */ - u8_t lcp_echo_interval; /* Interval between LCP echo-requests */ - u8_t lcp_echo_fails; /* Tolerance to unanswered echo-requests */ - -} ppp_settings; - -#if PPP_SERVER -struct ppp_addrs { -#if PPP_IPV4_SUPPORT - ip4_addr_t our_ipaddr, his_ipaddr, netmask; -#if LWIP_DNS - ip4_addr_t dns1, dns2; -#endif /* LWIP_DNS */ -#endif /* PPP_IPV4_SUPPORT */ -#if PPP_IPV6_SUPPORT - ip6_addr_t our6_ipaddr, his6_ipaddr; -#endif /* PPP_IPV6_SUPPORT */ -}; -#endif /* PPP_SERVER */ - -/* - * PPP interface control block. - */ -struct ppp_pcb_s { - ppp_settings settings; - const struct link_callbacks *link_cb; - void *link_ctx_cb; - void (*link_status_cb)(ppp_pcb *pcb, int err_code, void *ctx); /* Status change callback */ -#if PPP_NOTIFY_PHASE - void (*notify_phase_cb)(ppp_pcb *pcb, u8_t phase, void *ctx); /* Notify phase callback */ -#endif /* PPP_NOTIFY_PHASE */ - void *ctx_cb; /* Callbacks optional pointer */ - struct netif *netif; /* PPP interface */ - u8_t phase; /* where the link is at */ - u8_t err_code; /* Code indicating why interface is down. */ - - /* flags */ -#if PPP_IPV4_SUPPORT - unsigned int ask_for_local :1; /* request our address from peer */ - unsigned int ipcp_is_open :1; /* haven't called np_finished() */ - unsigned int ipcp_is_up :1; /* have called ipcp_up() */ - unsigned int if4_up :1; /* True when the IPv4 interface is up. */ -#if 0 /* UNUSED - PROXY ARP */ - unsigned int proxy_arp_set :1; /* Have created proxy arp entry */ -#endif /* UNUSED - PROXY ARP */ -#endif /* PPP_IPV4_SUPPORT */ -#if PPP_IPV6_SUPPORT - unsigned int ipv6cp_is_up :1; /* have called ip6cp_up() */ - unsigned int if6_up :1; /* True when the IPv6 interface is up. */ -#endif /* PPP_IPV6_SUPPORT */ - unsigned int lcp_echo_timer_running :1; /* set if a timer is running */ -#if VJ_SUPPORT - unsigned int vj_enabled :1; /* Flag indicating VJ compression enabled. */ -#endif /* VJ_SUPPORT */ -#if CCP_SUPPORT - unsigned int ccp_all_rejected :1; /* we rejected all peer's options */ -#endif /* CCP_SUPPORT */ -#if MPPE_SUPPORT - unsigned int mppe_keys_set :1; /* Have the MPPE keys been set? */ -#endif /* MPPE_SUPPORT */ - -#if PPP_AUTH_SUPPORT - /* auth data */ -#if PPP_SERVER && defined(HAVE_MULTILINK) - char peer_authname[MAXNAMELEN + 1]; /* The name by which the peer authenticated itself to us. */ -#endif /* PPP_SERVER && defined(HAVE_MULTILINK) */ - u16_t auth_pending; /* Records which authentication operations haven't completed yet. */ - u16_t auth_done; /* Records which authentication operations have been completed. */ - -#if PAP_SUPPORT - upap_state upap; /* PAP data */ -#endif /* PAP_SUPPORT */ - -#if CHAP_SUPPORT - chap_client_state chap_client; /* CHAP client data */ -#if PPP_SERVER - chap_server_state chap_server; /* CHAP server data */ -#endif /* PPP_SERVER */ -#endif /* CHAP_SUPPORT */ - -#if EAP_SUPPORT - eap_state eap; /* EAP data */ -#endif /* EAP_SUPPORT */ -#endif /* PPP_AUTH_SUPPORT */ - - fsm lcp_fsm; /* LCP fsm structure */ - lcp_options lcp_wantoptions; /* Options that we want to request */ - lcp_options lcp_gotoptions; /* Options that peer ack'd */ - lcp_options lcp_allowoptions; /* Options we allow peer to request */ - lcp_options lcp_hisoptions; /* Options that we ack'd */ - u16_t peer_mru; /* currently negotiated peer MRU */ - u8_t lcp_echos_pending; /* Number of outstanding echo msgs */ - u8_t lcp_echo_number; /* ID number of next echo frame */ - - u8_t num_np_open; /* Number of network protocols which we have opened. */ - u8_t num_np_up; /* Number of network protocols which have come up. */ - -#if VJ_SUPPORT - struct vjcompress vj_comp; /* Van Jacobson compression header. */ -#endif /* VJ_SUPPORT */ - -#if CCP_SUPPORT - fsm ccp_fsm; /* CCP fsm structure */ - ccp_options ccp_wantoptions; /* what to request the peer to use */ - ccp_options ccp_gotoptions; /* what the peer agreed to do */ - ccp_options ccp_allowoptions; /* what we'll agree to do */ - ccp_options ccp_hisoptions; /* what we agreed to do */ - u8_t ccp_localstate; /* Local state (mainly for handling reset-reqs and reset-acks). */ - u8_t ccp_receive_method; /* Method chosen on receive path */ - u8_t ccp_transmit_method; /* Method chosen on transmit path */ -#if MPPE_SUPPORT - ppp_mppe_state mppe_comp; /* MPPE "compressor" structure */ - ppp_mppe_state mppe_decomp; /* MPPE "decompressor" structure */ -#endif /* MPPE_SUPPORT */ -#endif /* CCP_SUPPORT */ - -#if PPP_IPV4_SUPPORT - fsm ipcp_fsm; /* IPCP fsm structure */ - ipcp_options ipcp_wantoptions; /* Options that we want to request */ - ipcp_options ipcp_gotoptions; /* Options that peer ack'd */ - ipcp_options ipcp_allowoptions; /* Options we allow peer to request */ - ipcp_options ipcp_hisoptions; /* Options that we ack'd */ -#endif /* PPP_IPV4_SUPPORT */ - -#if PPP_IPV6_SUPPORT - fsm ipv6cp_fsm; /* IPV6CP fsm structure */ - ipv6cp_options ipv6cp_wantoptions; /* Options that we want to request */ - ipv6cp_options ipv6cp_gotoptions; /* Options that peer ack'd */ - ipv6cp_options ipv6cp_allowoptions; /* Options we allow peer to request */ - ipv6cp_options ipv6cp_hisoptions; /* Options that we ack'd */ -#endif /* PPP_IPV6_SUPPORT */ -}; - -/************************ - *** PUBLIC FUNCTIONS *** - ************************/ - -/* - * WARNING: For multi-threads environment, all ppp_set_* functions most - * only be called while the PPP is in the dead phase (i.e. disconnected). - */ - -#if PPP_AUTH_SUPPORT -/* - * Set PPP authentication. - * - * Warning: Using PPPAUTHTYPE_ANY might have security consequences. - * RFC 1994 says: - * - * In practice, within or associated with each PPP server, there is a - * database which associates "user" names with authentication - * information ("secrets"). It is not anticipated that a particular - * named user would be authenticated by multiple methods. This would - * make the user vulnerable to attacks which negotiate the least secure - * method from among a set (such as PAP rather than CHAP). If the same - * secret was used, PAP would reveal the secret to be used later with - * CHAP. - * - * Instead, for each user name there should be an indication of exactly - * one method used to authenticate that user name. If a user needs to - * make use of different authentication methods under different - * circumstances, then distinct user names SHOULD be employed, each of - * which identifies exactly one authentication method. - * - * Default is none auth type, unset (NULL) user and passwd. - */ -#define PPPAUTHTYPE_NONE 0x00 -#define PPPAUTHTYPE_PAP 0x01 -#define PPPAUTHTYPE_CHAP 0x02 -#define PPPAUTHTYPE_MSCHAP 0x04 -#define PPPAUTHTYPE_MSCHAP_V2 0x08 -#define PPPAUTHTYPE_EAP 0x10 -#define PPPAUTHTYPE_ANY 0xff -void ppp_set_auth(ppp_pcb *pcb, u8_t authtype, const char *user, const char *passwd); - -/* - * If set, peer is required to authenticate. This is mostly necessary for PPP server support. - * - * Default is false. - */ -#define ppp_set_auth_required(ppp, boolval) (ppp->settings.auth_required = boolval) -#endif /* PPP_AUTH_SUPPORT */ - -#if PPP_IPV4_SUPPORT -/* - * Set PPP interface "our" and "his" IPv4 addresses. This is mostly necessary for PPP server - * support but it can also be used on a PPP link where each side choose its own IP address. - * - * Default is unset (0.0.0.0). - */ -#define ppp_set_ipcp_ouraddr(ppp, addr) do { ppp->ipcp_wantoptions.ouraddr = ip4_addr_get_u32(addr); \ - ppp->ask_for_local = ppp->ipcp_wantoptions.ouraddr != 0; } while(0) -#define ppp_set_ipcp_hisaddr(ppp, addr) (ppp->ipcp_wantoptions.hisaddr = ip4_addr_get_u32(addr)) -#if LWIP_DNS -/* - * Set DNS server addresses that are sent if the peer asks for them. This is mostly necessary - * for PPP server support. - * - * Default is unset (0.0.0.0). - */ -#define ppp_set_ipcp_dnsaddr(ppp, index, addr) (ppp->ipcp_allowoptions.dnsaddr[index] = ip4_addr_get_u32(addr)) - -/* - * If set, we ask the peer for up to 2 DNS server addresses. Received DNS server addresses are - * registered using the dns_setserver() function. - * - * Default is false. - */ -#define ppp_set_usepeerdns(ppp, boolval) (ppp->settings.usepeerdns = boolval) -#endif /* LWIP_DNS */ -#endif /* PPP_IPV4_SUPPORT */ - -#if MPPE_SUPPORT -/* Disable MPPE (Microsoft Point to Point Encryption). This parameter is exclusive. */ -#define PPP_MPPE_DISABLE 0x00 -/* Require the use of MPPE (Microsoft Point to Point Encryption). */ -#define PPP_MPPE_ENABLE 0x01 -/* Allow MPPE to use stateful mode. Stateless mode is still attempted first. */ -#define PPP_MPPE_ALLOW_STATEFUL 0x02 -/* Refuse the use of MPPE with 40-bit encryption. Conflict with PPP_MPPE_REFUSE_128. */ -#define PPP_MPPE_REFUSE_40 0x04 -/* Refuse the use of MPPE with 128-bit encryption. Conflict with PPP_MPPE_REFUSE_40. */ -#define PPP_MPPE_REFUSE_128 0x08 -/* - * Set MPPE configuration - * - * Default is disabled. - */ -void ppp_set_mppe(ppp_pcb *pcb, u8_t flags); -#endif /* MPPE_SUPPORT */ - -/* - * Wait for up to intval milliseconds for a valid PPP packet from the peer. - * At the end of this time, or when a valid PPP packet is received from the - * peer, we commence negotiation by sending our first LCP packet. - * - * Default is 0. - */ -#define ppp_set_listen_time(ppp, intval) (ppp->settings.listen_time = intval) - -/* - * If set, we will attempt to initiate a connection but if no reply is received from - * the peer, we will then just wait passively for a valid LCP packet from the peer. - * - * Default is false. - */ -#define ppp_set_passive(ppp, boolval) (ppp->lcp_wantoptions.passive = boolval) - -/* - * If set, we will not transmit LCP packets to initiate a connection until a valid - * LCP packet is received from the peer. This is what we usually call the server mode. - * - * Default is false. - */ -#define ppp_set_silent(ppp, boolval) (ppp->lcp_wantoptions.silent = boolval) - -/* - * If set, enable protocol field compression negotiation in both the receive and - * the transmit direction. - * - * Default is true. - */ -#define ppp_set_neg_pcomp(ppp, boolval) (ppp->lcp_wantoptions.neg_pcompression = \ - ppp->lcp_allowoptions.neg_pcompression = boolval) - -/* - * If set, enable Address/Control compression in both the receive and the transmit - * direction. - * - * Default is true. - */ -#define ppp_set_neg_accomp(ppp, boolval) (ppp->lcp_wantoptions.neg_accompression = \ - ppp->lcp_allowoptions.neg_accompression = boolval) - -/* - * If set, enable asyncmap negotiation. Otherwise forcing all control characters to - * be escaped for both the transmit and the receive direction. - * - * Default is true. - */ -#define ppp_set_neg_asyncmap(ppp, boolval) (ppp->lcp_wantoptions.neg_asyncmap = \ - ppp->lcp_allowoptions.neg_asyncmap = boolval) - -/* - * This option sets the Async-Control-Character-Map (ACCM) for this end of the link. - * The ACCM is a set of 32 bits, one for each of the ASCII control characters with - * values from 0 to 31, where a 1 bit indicates that the corresponding control - * character should not be used in PPP packets sent to this system. The map is - * an unsigned 32 bits integer where the least significant bit (00000001) represents - * character 0 and the most significant bit (80000000) represents character 31. - * We will then ask the peer to send these characters as a 2-byte escape sequence. - * - * Default is 0. - */ -#define ppp_set_asyncmap(ppp, intval) (ppp->lcp_wantoptions.asyncmap = intval) - -/* - * Set a PPP interface as the default network interface - * (used to output all packets for which no specific route is found). - */ -#define ppp_set_default(ppp) netif_set_default(ppp->netif) - -#if PPP_NOTIFY_PHASE -/* - * Set a PPP notify phase callback. - * - * This can be used for example to set a LED pattern depending on the - * current phase of the PPP session. - */ -typedef void (*ppp_notify_phase_cb_fn)(ppp_pcb *pcb, u8_t phase, void *ctx); -void ppp_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb); -#endif /* PPP_NOTIFY_PHASE */ - -/* - * Initiate a PPP connection. - * - * This can only be called if PPP is in the dead phase. - * - * Holdoff is the time to wait (in seconds) before initiating - * the connection. - * - * If this port connects to a modem, the modem connection must be - * established before calling this. - */ -err_t ppp_connect(ppp_pcb *pcb, u16_t holdoff); - -#if PPP_SERVER -/* - * Listen for an incoming PPP connection. - * - * This can only be called if PPP is in the dead phase. - * - * If this port connects to a modem, the modem connection must be - * established before calling this. - */ -err_t ppp_listen(ppp_pcb *pcb); -#endif /* PPP_SERVER */ - -/* - * Initiate the end of a PPP connection. - * Any outstanding packets in the queues are dropped. - * - * Setting nocarrier to 1 close the PPP connection without initiating the - * shutdown procedure. Always using nocarrier = 0 is still recommended, - * this is going to take a little longer time if your link is down, but - * is a safer choice for the PPP state machine. - * - * Return 0 on success, an error code on failure. - */ -err_t ppp_close(ppp_pcb *pcb, u8_t nocarrier); - -/* - * Release the control block. - * - * This can only be called if PPP is in the dead phase. - * - * You must use ppp_close() before if you wish to terminate - * an established PPP session. - * - * Return 0 on success, an error code on failure. - */ -err_t ppp_free(ppp_pcb *pcb); - -/* - * PPP IOCTL commands. - * - * Get the up status - 0 for down, non-zero for up. The argument must - * point to an int. - */ -#define PPPCTLG_UPSTATUS 0 - -/* - * Get the PPP error code. The argument must point to an int. - * Returns a PPPERR_* value. - */ -#define PPPCTLG_ERRCODE 1 - -/* - * Get the fd associated with a PPP over serial - */ -#define PPPCTLG_FD 2 - -/* - * Get and set parameters for the given connection. - * Return 0 on success, an error code on failure. - */ -err_t ppp_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg); - -/* Get the PPP netif interface */ -#define ppp_netif(ppp) (ppp->netif) - -/* Set an lwIP-style status-callback for the selected PPP device */ -#define ppp_set_netif_statuscallback(ppp, status_cb) \ - netif_set_status_callback(ppp->netif, status_cb); - -/* Set an lwIP-style link-callback for the selected PPP device */ -#define ppp_set_netif_linkcallback(ppp, link_cb) \ - netif_set_link_callback(ppp->netif, link_cb); - -#ifdef __cplusplus -} -#endif - -#endif /* PPP_H */ - -#endif /* PPP_SUPPORT */ diff --git a/core/c/include/netif/ppp/ppp_impl.h b/core/c/include/netif/ppp/ppp_impl.h deleted file mode 100755 index 280ff00..0000000 --- a/core/c/include/netif/ppp/ppp_impl.h +++ /dev/null @@ -1,722 +0,0 @@ -/***************************************************************************** -* ppp.h - Network Point to Point Protocol header file. -* -* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. -* portions Copyright (c) 1997 Global Election Systems 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 -* -* 03-01-01 Marc Boucher -* Ported to lwIP. -* 97-11-05 Guy Lancaster , Global Election Systems Inc. -* Original derived from BSD codes. -*****************************************************************************/ -#ifndef LWIP_HDR_PPP_IMPL_H -#define LWIP_HDR_PPP_IMPL_H - -#include "netif/ppp/ppp_opts.h" - -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifdef PPP_INCLUDE_SETTINGS_HEADER -#include "ppp_settings.h" -#endif - -#include /* formats */ -#include -#include -#include /* strtol() */ - -#include "lwip/netif.h" -#include "lwip/def.h" -#include "lwip/timeouts.h" - -#include "ppp.h" -#include "pppdebug.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Memory used for control packets. - * - * PPP_CTRL_PBUF_MAX_SIZE is the amount of memory we allocate when we - * cannot figure out how much we are going to use before filling the buffer. - */ -#if PPP_USE_PBUF_RAM -#define PPP_CTRL_PBUF_TYPE PBUF_RAM -#define PPP_CTRL_PBUF_MAX_SIZE 512 -#else /* PPP_USE_PBUF_RAM */ -#define PPP_CTRL_PBUF_TYPE PBUF_POOL -#define PPP_CTRL_PBUF_MAX_SIZE PBUF_POOL_BUFSIZE -#endif /* PPP_USE_PBUF_RAM */ - -/* - * The basic PPP frame. - */ -#define PPP_ADDRESS(p) (((u_char *)(p))[0]) -#define PPP_CONTROL(p) (((u_char *)(p))[1]) -#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3]) - -/* - * Significant octet values. - */ -#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ -#define PPP_UI 0x03 /* Unnumbered Information */ -#define PPP_FLAG 0x7e /* Flag Sequence */ -#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ -#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ - -/* - * Protocol field values. - */ -#define PPP_IP 0x21 /* Internet Protocol */ -#if 0 /* UNUSED */ -#define PPP_AT 0x29 /* AppleTalk Protocol */ -#define PPP_IPX 0x2b /* IPX protocol */ -#endif /* UNUSED */ -#if VJ_SUPPORT -#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ -#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ -#endif /* VJ_SUPPORT */ -#if PPP_IPV6_SUPPORT -#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ -#endif /* PPP_IPV6_SUPPORT */ -#if CCP_SUPPORT -#define PPP_COMP 0xfd /* compressed packet */ -#endif /* CCP_SUPPORT */ -#define PPP_IPCP 0x8021 /* IP Control Protocol */ -#if 0 /* UNUSED */ -#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ -#define PPP_IPXCP 0x802b /* IPX Control Protocol */ -#endif /* UNUSED */ -#if PPP_IPV6_SUPPORT -#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ -#endif /* PPP_IPV6_SUPPORT */ -#if CCP_SUPPORT -#define PPP_CCP 0x80fd /* Compression Control Protocol */ -#endif /* CCP_SUPPORT */ -#if ECP_SUPPORT -#define PPP_ECP 0x8053 /* Encryption Control Protocol */ -#endif /* ECP_SUPPORT */ -#define PPP_LCP 0xc021 /* Link Control Protocol */ -#if PAP_SUPPORT -#define PPP_PAP 0xc023 /* Password Authentication Protocol */ -#endif /* PAP_SUPPORT */ -#if LQR_SUPPORT -#define PPP_LQR 0xc025 /* Link Quality Report protocol */ -#endif /* LQR_SUPPORT */ -#if CHAP_SUPPORT -#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ -#endif /* CHAP_SUPPORT */ -#if CBCP_SUPPORT -#define PPP_CBCP 0xc029 /* Callback Control Protocol */ -#endif /* CBCP_SUPPORT */ -#if EAP_SUPPORT -#define PPP_EAP 0xc227 /* Extensible Authentication Protocol */ -#endif /* EAP_SUPPORT */ - -/* - * The following struct gives the addresses of procedures to call - * for a particular lower link level protocol. - */ -struct link_callbacks { - /* Start a connection (e.g. Initiate discovery phase) */ - void (*connect) (ppp_pcb *pcb, void *ctx); -#if PPP_SERVER - /* Listen for an incoming connection (Passive mode) */ - void (*listen) (ppp_pcb *pcb, void *ctx); -#endif /* PPP_SERVER */ - /* End a connection (i.e. initiate disconnect phase) */ - void (*disconnect) (ppp_pcb *pcb, void *ctx); - /* Free lower protocol control block */ - err_t (*free) (ppp_pcb *pcb, void *ctx); - /* Write a pbuf to a ppp link, only used from PPP functions to send PPP packets. */ - err_t (*write)(ppp_pcb *pcb, void *ctx, struct pbuf *p); - /* Send a packet from lwIP core (IPv4 or IPv6) */ - err_t (*netif_output)(ppp_pcb *pcb, void *ctx, struct pbuf *p, u_short protocol); - /* configure the transmit-side characteristics of the PPP interface */ - void (*send_config)(ppp_pcb *pcb, void *ctx, u32_t accm, int pcomp, int accomp); - /* confire the receive-side characteristics of the PPP interface */ - void (*recv_config)(ppp_pcb *pcb, void *ctx, u32_t accm, int pcomp, int accomp); -}; - -/* - * What to do with network protocol (NP) packets. - */ -enum NPmode { - NPMODE_PASS, /* pass the packet through */ - NPMODE_DROP, /* silently drop the packet */ - NPMODE_ERROR, /* return an error */ - NPMODE_QUEUE /* save it up for later. */ -}; - -/* - * Statistics. - */ -#if PPP_STATS_SUPPORT -struct pppstat { - unsigned int ppp_ibytes; /* bytes received */ - unsigned int ppp_ipackets; /* packets received */ - unsigned int ppp_ierrors; /* receive errors */ - unsigned int ppp_obytes; /* bytes sent */ - unsigned int ppp_opackets; /* packets sent */ - unsigned int ppp_oerrors; /* transmit errors */ -}; - -#if VJ_SUPPORT -struct vjstat { - unsigned int vjs_packets; /* outbound packets */ - unsigned int vjs_compressed; /* outbound compressed packets */ - unsigned int vjs_searches; /* searches for connection state */ - unsigned int vjs_misses; /* times couldn't find conn. state */ - unsigned int vjs_uncompressedin; /* inbound uncompressed packets */ - unsigned int vjs_compressedin; /* inbound compressed packets */ - unsigned int vjs_errorin; /* inbound unknown type packets */ - unsigned int vjs_tossed; /* inbound packets tossed because of error */ -}; -#endif /* VJ_SUPPORT */ - -struct ppp_stats { - struct pppstat p; /* basic PPP statistics */ -#if VJ_SUPPORT - struct vjstat vj; /* VJ header compression statistics */ -#endif /* VJ_SUPPORT */ -}; - -#if CCP_SUPPORT -struct compstat { - unsigned int unc_bytes; /* total uncompressed bytes */ - unsigned int unc_packets; /* total uncompressed packets */ - unsigned int comp_bytes; /* compressed bytes */ - unsigned int comp_packets; /* compressed packets */ - unsigned int inc_bytes; /* incompressible bytes */ - unsigned int inc_packets; /* incompressible packets */ - unsigned int ratio; /* recent compression ratio << 8 */ -}; - -struct ppp_comp_stats { - struct compstat c; /* packet compression statistics */ - struct compstat d; /* packet decompression statistics */ -}; -#endif /* CCP_SUPPORT */ - -#endif /* PPP_STATS_SUPPORT */ - -#if PPP_IDLETIMELIMIT -/* - * The following structure records the time in seconds since - * the last NP packet was sent or received. - */ -struct ppp_idle { - time_t xmit_idle; /* time since last NP packet sent */ - time_t recv_idle; /* time since last NP packet received */ -}; -#endif /* PPP_IDLETIMELIMIT */ - -/* values for epdisc.class */ -#define EPD_NULL 0 /* null discriminator, no data */ -#define EPD_LOCAL 1 -#define EPD_IP 2 -#define EPD_MAC 3 -#define EPD_MAGIC 4 -#define EPD_PHONENUM 5 - -/* - * Global variables. - */ -#ifdef HAVE_MULTILINK -extern u8_t multilink; /* enable multilink operation */ -extern u8_t doing_multilink; -extern u8_t multilink_master; -extern u8_t bundle_eof; -extern u8_t bundle_terminating; -#endif - -#ifdef MAXOCTETS -extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */ -extern int maxoctets_dir; /* Direction : - 0 - in+out (default) - 1 - in - 2 - out - 3 - max(in,out) */ -extern int maxoctets_timeout; /* Timeout for check of octets limit */ -#define PPP_OCTETS_DIRECTION_SUM 0 -#define PPP_OCTETS_DIRECTION_IN 1 -#define PPP_OCTETS_DIRECTION_OUT 2 -#define PPP_OCTETS_DIRECTION_MAXOVERAL 3 -/* same as previos, but little different on RADIUS side */ -#define PPP_OCTETS_DIRECTION_MAXSESSION 4 -#endif - -/* Data input may be used by CCP and ECP, remove this entry - * from struct protent to save some flash - */ -#define PPP_DATAINPUT 0 - -/* - * The following struct gives the addresses of procedures to call - * for a particular protocol. - */ -struct protent { - u_short protocol; /* PPP protocol number */ - /* Initialization procedure */ - void (*init) (ppp_pcb *pcb); - /* Process a received packet */ - void (*input) (ppp_pcb *pcb, u_char *pkt, int len); - /* Process a received protocol-reject */ - void (*protrej) (ppp_pcb *pcb); - /* Lower layer has come up */ - void (*lowerup) (ppp_pcb *pcb); - /* Lower layer has gone down */ - void (*lowerdown) (ppp_pcb *pcb); - /* Open the protocol */ - void (*open) (ppp_pcb *pcb); - /* Close the protocol */ - void (*close) (ppp_pcb *pcb, const char *reason); -#if PRINTPKT_SUPPORT - /* Print a packet in readable form */ - int (*printpkt) (const u_char *pkt, int len, - void (*printer) (void *, const char *, ...), - void *arg); -#endif /* PRINTPKT_SUPPORT */ -#if PPP_DATAINPUT - /* Process a received data packet */ - void (*datainput) (ppp_pcb *pcb, u_char *pkt, int len); -#endif /* PPP_DATAINPUT */ -#if PRINTPKT_SUPPORT - const char *name; /* Text name of protocol */ - const char *data_name; /* Text name of corresponding data protocol */ -#endif /* PRINTPKT_SUPPORT */ -#if PPP_OPTIONS - option_t *options; /* List of command-line options */ - /* Check requested options, assign defaults */ - void (*check_options) (void); -#endif /* PPP_OPTIONS */ -#if DEMAND_SUPPORT - /* Configure interface for demand-dial */ - int (*demand_conf) (int unit); - /* Say whether to bring up link for this pkt */ - int (*active_pkt) (u_char *pkt, int len); -#endif /* DEMAND_SUPPORT */ -}; - -/* Table of pointers to supported protocols */ -extern const struct protent* const protocols[]; - - -/* Values for auth_pending, auth_done */ -#if PAP_SUPPORT -#define PAP_WITHPEER 0x1 -#define PAP_PEER 0x2 -#endif /* PAP_SUPPORT */ -#if CHAP_SUPPORT -#define CHAP_WITHPEER 0x4 -#define CHAP_PEER 0x8 -#endif /* CHAP_SUPPORT */ -#if EAP_SUPPORT -#define EAP_WITHPEER 0x10 -#define EAP_PEER 0x20 -#endif /* EAP_SUPPORT */ - -/* Values for auth_done only */ -#if CHAP_SUPPORT -#define CHAP_MD5_WITHPEER 0x40 -#define CHAP_MD5_PEER 0x80 -#if MSCHAP_SUPPORT -#define CHAP_MS_SHIFT 8 /* LSB position for MS auths */ -#define CHAP_MS_WITHPEER 0x100 -#define CHAP_MS_PEER 0x200 -#define CHAP_MS2_WITHPEER 0x400 -#define CHAP_MS2_PEER 0x800 -#endif /* MSCHAP_SUPPORT */ -#endif /* CHAP_SUPPORT */ - -/* Supported CHAP protocols */ -#if CHAP_SUPPORT - -#if MSCHAP_SUPPORT -#define CHAP_MDTYPE_SUPPORTED (MDTYPE_MICROSOFT_V2 | MDTYPE_MICROSOFT | MDTYPE_MD5) -#else /* MSCHAP_SUPPORT */ -#define CHAP_MDTYPE_SUPPORTED (MDTYPE_MD5) -#endif /* MSCHAP_SUPPORT */ - -#else /* CHAP_SUPPORT */ -#define CHAP_MDTYPE_SUPPORTED (MDTYPE_NONE) -#endif /* CHAP_SUPPORT */ - -#if PPP_STATS_SUPPORT -/* - * PPP statistics structure - */ -struct pppd_stats { - unsigned int bytes_in; - unsigned int bytes_out; - unsigned int pkts_in; - unsigned int pkts_out; -}; -#endif /* PPP_STATS_SUPPORT */ - - -/* - * PPP private functions - */ - - -/* - * Functions called from lwIP core. - */ - -/* initialize the PPP subsystem */ -int ppp_init(void); - -/* - * Functions called from PPP link protocols. - */ - -/* Create a new PPP control block */ -ppp_pcb *ppp_new(struct netif *pppif, const struct link_callbacks *callbacks, void *link_ctx_cb, - ppp_link_status_cb_fn link_status_cb, void *ctx_cb); - -/* Initiate LCP open request */ -void ppp_start(ppp_pcb *pcb); - -/* Called when link failed to setup */ -void ppp_link_failed(ppp_pcb *pcb); - -/* Called when link is normally down (i.e. it was asked to end) */ -void ppp_link_end(ppp_pcb *pcb); - -/* function called to process input packet */ -void ppp_input(ppp_pcb *pcb, struct pbuf *pb); - - -/* - * Functions called by PPP protocols. - */ - -/* function called by all PPP subsystems to send packets */ -err_t ppp_write(ppp_pcb *pcb, struct pbuf *p); - -/* functions called by auth.c link_terminated() */ -void ppp_link_terminated(ppp_pcb *pcb); - -void new_phase(ppp_pcb *pcb, int p); - -int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp); -int ppp_recv_config(ppp_pcb *pcb, int mru, u32_t accm, int pcomp, int accomp); - -#if PPP_IPV4_SUPPORT -int sifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr, u32_t netmask); -int cifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr); -#if 0 /* UNUSED - PROXY ARP */ -int sifproxyarp(ppp_pcb *pcb, u32_t his_adr); -int cifproxyarp(ppp_pcb *pcb, u32_t his_adr); -#endif /* UNUSED - PROXY ARP */ -#if LWIP_DNS -int sdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2); -int cdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2); -#endif /* LWIP_DNS */ -#if VJ_SUPPORT -int sifvjcomp(ppp_pcb *pcb, int vjcomp, int cidcomp, int maxcid); -#endif /* VJ_SUPPORT */ -int sifup(ppp_pcb *pcb); -int sifdown (ppp_pcb *pcb); -u32_t get_mask(u32_t addr); -#endif /* PPP_IPV4_SUPPORT */ - -#if PPP_IPV6_SUPPORT -int sif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64); -int cif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64); -int sif6up(ppp_pcb *pcb); -int sif6down (ppp_pcb *pcb); -#endif /* PPP_IPV6_SUPPORT */ - -#if DEMAND_SUPPORT -int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode); -#endif /* DEMAND_SUPPORt */ - -void netif_set_mtu(ppp_pcb *pcb, int mtu); -int netif_get_mtu(ppp_pcb *pcb); - -#if CCP_SUPPORT -#if 0 /* unused */ -int ccp_test(ppp_pcb *pcb, u_char *opt_ptr, int opt_len, int for_transmit); -#endif /* unused */ -void ccp_set(ppp_pcb *pcb, u8_t isopen, u8_t isup, u8_t receive_method, u8_t transmit_method); -void ccp_reset_comp(ppp_pcb *pcb); -void ccp_reset_decomp(ppp_pcb *pcb); -#if 0 /* unused */ -int ccp_fatal_error(ppp_pcb *pcb); -#endif /* unused */ -#endif /* CCP_SUPPORT */ - -#if PPP_IDLETIMELIMIT -int get_idle_time(ppp_pcb *pcb, struct ppp_idle *ip); -#endif /* PPP_IDLETIMELIMIT */ - -#if DEMAND_SUPPORT -int get_loop_output(void); -#endif /* DEMAND_SUPPORT */ - -/* Optional protocol names list, to make our messages a little more informative. */ -#if PPP_PROTOCOLNAME -const char * protocol_name(int proto); -#endif /* PPP_PROTOCOLNAME */ - -/* Optional stats support, to get some statistics on the PPP interface */ -#if PPP_STATS_SUPPORT -void print_link_stats(void); /* Print stats, if available */ -void reset_link_stats(int u); /* Reset (init) stats when link goes up */ -void update_link_stats(int u); /* Get stats at link termination */ -#endif /* PPP_STATS_SUPPORT */ - - - -/* - * Inline versions of get/put char/short/long. - * Pointer is advanced; we assume that both arguments - * are lvalues and will already be in registers. - * cp MUST be u_char *. - */ -#define GETCHAR(c, cp) { \ - (c) = *(cp)++; \ -} -#define PUTCHAR(c, cp) { \ - *(cp)++ = (u_char) (c); \ -} -#define GETSHORT(s, cp) { \ - (s) = *(cp)++ << 8; \ - (s) |= *(cp)++; \ -} -#define PUTSHORT(s, cp) { \ - *(cp)++ = (u_char) ((s) >> 8); \ - *(cp)++ = (u_char) (s); \ -} -#define GETLONG(l, cp) { \ - (l) = *(cp)++ << 8; \ - (l) |= *(cp)++; (l) <<= 8; \ - (l) |= *(cp)++; (l) <<= 8; \ - (l) |= *(cp)++; \ -} -#define PUTLONG(l, cp) { \ - *(cp)++ = (u_char) ((l) >> 24); \ - *(cp)++ = (u_char) ((l) >> 16); \ - *(cp)++ = (u_char) ((l) >> 8); \ - *(cp)++ = (u_char) (l); \ -} - -#define INCPTR(n, cp) ((cp) += (n)) -#define DECPTR(n, cp) ((cp) -= (n)) - -/* - * System dependent definitions for user-level 4.3BSD UNIX implementation. - */ -#define TIMEOUT(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t)*1000, (f), (a)); } while(0) -#define TIMEOUTMS(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t), (f), (a)); } while(0) -#define UNTIMEOUT(f, a) sys_untimeout((f), (a)) - -#define BZERO(s, n) memset(s, 0, n) -#define BCMP(s1, s2, l) memcmp(s1, s2, l) - -#define PRINTMSG(m, l) { ppp_info("Remote message: %0.*v", l, m); } - -/* - * MAKEHEADER - Add Header fields to a packet. - */ -#define MAKEHEADER(p, t) { \ - PUTCHAR(PPP_ALLSTATIONS, p); \ - PUTCHAR(PPP_UI, p); \ - PUTSHORT(t, p); } - -/* Procedures exported from auth.c */ -void link_required(ppp_pcb *pcb); /* we are starting to use the link */ -void link_terminated(ppp_pcb *pcb); /* we are finished with the link */ -void link_down(ppp_pcb *pcb); /* the LCP layer has left the Opened state */ -void upper_layers_down(ppp_pcb *pcb); /* take all NCPs down */ -void link_established(ppp_pcb *pcb); /* the link is up; authenticate now */ -void start_networks(ppp_pcb *pcb); /* start all the network control protos */ -void continue_networks(ppp_pcb *pcb); /* start network [ip, etc] control protos */ -#if PPP_AUTH_SUPPORT -#if PPP_SERVER -int auth_check_passwd(ppp_pcb *pcb, char *auser, int userlen, char *apasswd, int passwdlen, const char **msg, int *msglen); - /* check the user name and passwd against configuration */ -void auth_peer_fail(ppp_pcb *pcb, int protocol); - /* peer failed to authenticate itself */ -void auth_peer_success(ppp_pcb *pcb, int protocol, int prot_flavor, const char *name, int namelen); - /* peer successfully authenticated itself */ -#endif /* PPP_SERVER */ -void auth_withpeer_fail(ppp_pcb *pcb, int protocol); - /* we failed to authenticate ourselves */ -void auth_withpeer_success(ppp_pcb *pcb, int protocol, int prot_flavor); - /* we successfully authenticated ourselves */ -#endif /* PPP_AUTH_SUPPORT */ -void np_up(ppp_pcb *pcb, int proto); /* a network protocol has come up */ -void np_down(ppp_pcb *pcb, int proto); /* a network protocol has gone down */ -void np_finished(ppp_pcb *pcb, int proto); /* a network protocol no longer needs link */ -#if PPP_AUTH_SUPPORT -int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secret, int *secret_len, int am_server); - /* get "secret" for chap */ -#endif /* PPP_AUTH_SUPPORT */ - -/* Procedures exported from ipcp.c */ -/* int parse_dotted_ip (char *, u32_t *); */ - -/* Procedures exported from demand.c */ -#if DEMAND_SUPPORT -void demand_conf (void); /* config interface(s) for demand-dial */ -void demand_block (void); /* set all NPs to queue up packets */ -void demand_unblock (void); /* set all NPs to pass packets */ -void demand_discard (void); /* set all NPs to discard packets */ -void demand_rexmit (int, u32_t); /* retransmit saved frames for an NP*/ -int loop_chars (unsigned char *, int); /* process chars from loopback */ -int loop_frame (unsigned char *, int); /* should we bring link up? */ -#endif /* DEMAND_SUPPORT */ - -/* Procedures exported from multilink.c */ -#ifdef HAVE_MULTILINK -void mp_check_options (void); /* Check multilink-related options */ -int mp_join_bundle (void); /* join our link to an appropriate bundle */ -void mp_exit_bundle (void); /* have disconnected our link from bundle */ -void mp_bundle_terminated (void); -char *epdisc_to_str (struct epdisc *); /* string from endpoint discrim. */ -int str_to_epdisc (struct epdisc *, char *); /* endpt disc. from str */ -#else -#define mp_bundle_terminated() /* nothing */ -#define mp_exit_bundle() /* nothing */ -#define doing_multilink 0 -#define multilink_master 0 -#endif - -/* Procedures exported from utils.c. */ -void ppp_print_string(const u_char *p, int len, void (*printer) (void *, const char *, ...), void *arg); /* Format a string for output */ -int ppp_slprintf(char *buf, int buflen, const char *fmt, ...); /* sprintf++ */ -int ppp_vslprintf(char *buf, int buflen, const char *fmt, va_list args); /* vsprintf++ */ -size_t ppp_strlcpy(char *dest, const char *src, size_t len); /* safe strcpy */ -size_t ppp_strlcat(char *dest, const char *src, size_t len); /* safe strncpy */ -void ppp_dbglog(const char *fmt, ...); /* log a debug message */ -void ppp_info(const char *fmt, ...); /* log an informational message */ -void ppp_notice(const char *fmt, ...); /* log a notice-level message */ -void ppp_warn(const char *fmt, ...); /* log a warning message */ -void ppp_error(const char *fmt, ...); /* log an error message */ -void ppp_fatal(const char *fmt, ...); /* log an error message and die(1) */ -#if PRINTPKT_SUPPORT -void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len); - /* dump packet to debug log if interesting */ -#endif /* PRINTPKT_SUPPORT */ - -/* - * Number of necessary timers analysis. - * - * PPP use at least one timer per each of its protocol, but not all protocols are - * active at the same time, thus the number of necessary timeouts is actually - * lower than enabled protocols. Here is the actual necessary timeouts based - * on code analysis. - * - * Note that many features analysed here are not working at all and are only - * there for a comprehensive analysis of necessary timers in order to prevent - * having to redo that each time we add a feature. - * - * Timer list - * - * | holdoff timeout - * | low level protocol timeout (PPPoE or PPPoL2P) - * | LCP delayed UP - * | LCP retransmit (FSM) - * | LCP Echo timer - * .| PAP or CHAP or EAP authentication - * . | ECP retransmit (FSM) - * . | CCP retransmit (FSM) when MPPE is enabled - * . | CCP retransmit (FSM) when MPPE is NOT enabled - * . | IPCP retransmit (FSM) - * . .| IP6CP retransmit (FSM) - * . . | Idle time limit - * . . | Max connect time - * . . | Max octets - * . . | CCP RACK timeout - * . . . - * PPP_PHASE_DEAD - * PPP_PHASE_HOLDOFF - * | . . . - * PPP_PHASE_INITIALIZE - * | . . . - * PPP_PHASE_ESTABLISH - * | . . . - * |. . . - * | . . - * PPP_PHASE_AUTHENTICATE - * | . . - * || . . - * PPP_PHASE_NETWORK - * | || . . - * | ||| . - * PPP_PHASE_RUNNING - * | .||||| - * | . |||| - * PPP_PHASE_TERMINATE - * | . |||| - * PPP_PHASE_NETWORK - * |. . - * PPP_PHASE_ESTABLISH - * PPP_PHASE_DISCONNECT - * PPP_PHASE_DEAD - * - * Alright, PPP basic retransmission and LCP Echo consume one timer. - * 1 - * - * If authentication is enabled one timer is necessary during authentication. - * 1 + PPP_AUTH_SUPPORT - * - * If ECP is enabled one timer is necessary before IPCP and/or IP6CP, one more - * is necessary if CCP is enabled (only with MPPE support but we don't care much - * up to this detail level). - * 1 + ECP_SUPPORT + CCP_SUPPORT - * - * If CCP is enabled it might consume a timer during IPCP or IP6CP, thus - * we might use IPCP, IP6CP and CCP timers simultaneously. - * 1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT - * - * When entering running phase, IPCP or IP6CP is still running. If idle time limit - * is enabled one more timer is necessary. Same for max connect time and max - * octets features. Furthermore CCP RACK might be used past this point. - * 1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS + CCP_SUPPORT - * - * IPv4 or IPv6 must be enabled, therefore we don't need to take care the authentication - * and the CCP + ECP case, thus reducing overall complexity. - * 1 + LWIP_MAX(PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT, PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS + CCP_SUPPORT) - * - * We don't support PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS features - * and adding those defines to ppp_opts.h just for having the value always - * defined to 0 isn't worth it. - * 1 + LWIP_MAX(PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT, PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + CCP_SUPPORT) - * - * Thus, the following is enough for now. - * 1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT - */ - -#ifdef __cplusplus -} -#endif - -#endif /* PPP_SUPPORT */ -#endif /* LWIP_HDR_PPP_IMPL_H */ diff --git a/core/c/include/netif/ppp/ppp_opts.h b/core/c/include/netif/ppp/ppp_opts.h deleted file mode 100755 index 502a2cc..0000000 --- a/core/c/include/netif/ppp/ppp_opts.h +++ /dev/null @@ -1,610 +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_PPP_OPTS_H -#define LWIP_PPP_OPTS_H - -#include "lwip/opt.h" - -/** - * 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 - -/** - * PPPOL2TP_SUPPORT==1: Enable PPP Over L2TP - */ -#ifndef PPPOL2TP_SUPPORT -#define PPPOL2TP_SUPPORT 0 -#endif - -/** - * PPPOL2TP_AUTH_SUPPORT==1: Enable PPP Over L2TP Auth (enable MD5 support) - */ -#ifndef PPPOL2TP_AUTH_SUPPORT -#define PPPOL2TP_AUTH_SUPPORT PPPOL2TP_SUPPORT -#endif - -/** - * PPPOS_SUPPORT==1: Enable PPP Over Serial - */ -#ifndef PPPOS_SUPPORT -#define PPPOS_SUPPORT PPP_SUPPORT -#endif - -/** - * LWIP_PPP_API==1: Enable PPP API (in pppapi.c) - */ -#ifndef LWIP_PPP_API -#define LWIP_PPP_API (PPP_SUPPORT && (NO_SYS == 0)) -#endif - -#if PPP_SUPPORT - -/** - * MEMP_NUM_PPP_PCB: the number of simultaneously active PPP - * connections (requires the PPP_SUPPORT option) - */ -#ifndef MEMP_NUM_PPP_PCB -#define MEMP_NUM_PPP_PCB 1 -#endif - -/** - * PPP_NUM_TIMEOUTS_PER_PCB: the number of sys_timeouts running in parallel per - * ppp_pcb. See the detailed explanation at the end of ppp_impl.h about simultaneous - * timers analysis. - */ -#ifndef PPP_NUM_TIMEOUTS_PER_PCB -#define PPP_NUM_TIMEOUTS_PER_PCB (1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT) -#endif - -/* The number of sys_timeouts required for the PPP module */ -#define PPP_NUM_TIMEOUTS (PPP_SUPPORT * PPP_NUM_TIMEOUTS_PER_PCB * MEMP_NUM_PPP_PCB) - -/** - * MEMP_NUM_PPPOS_INTERFACES: the number of concurrently active PPPoS - * interfaces (only used with PPPOS_SUPPORT==1) - */ -#ifndef MEMP_NUM_PPPOS_INTERFACES -#define MEMP_NUM_PPPOS_INTERFACES MEMP_NUM_PPP_PCB -#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 - -/** - * MEMP_NUM_PPPOL2TP_INTERFACES: the number of concurrently active PPPoL2TP - * interfaces (only used with PPPOL2TP_SUPPORT==1) - */ -#ifndef MEMP_NUM_PPPOL2TP_INTERFACES -#define MEMP_NUM_PPPOL2TP_INTERFACES 1 -#endif - -/** - * MEMP_NUM_PPP_API_MSG: Number of concurrent PPP API messages (in pppapi.c) - */ -#ifndef MEMP_NUM_PPP_API_MSG -#define MEMP_NUM_PPP_API_MSG 5 -#endif - -/** - * PPP_DEBUG: Enable debugging for PPP. - */ -#ifndef PPP_DEBUG -#define PPP_DEBUG LWIP_DBG_OFF -#endif - -/** - * PPP_INPROC_IRQ_SAFE==1 call pppos_input() using tcpip_callback(). - * - * Please read the "PPPoS input path" chapter in the PPP documentation about this option. - */ -#ifndef PPP_INPROC_IRQ_SAFE -#define PPP_INPROC_IRQ_SAFE 0 -#endif - -/** - * PRINTPKT_SUPPORT==1: Enable PPP print packet support - * - * Mandatory for debugging, it displays exchanged packet content in debug trace. - */ -#ifndef PRINTPKT_SUPPORT -#define PRINTPKT_SUPPORT 0 -#endif - -/** - * PPP_IPV4_SUPPORT==1: Enable PPP IPv4 support - */ -#ifndef PPP_IPV4_SUPPORT -#define PPP_IPV4_SUPPORT (LWIP_IPV4) -#endif - -/** - * PPP_IPV6_SUPPORT==1: Enable PPP IPv6 support - */ -#ifndef PPP_IPV6_SUPPORT -#define PPP_IPV6_SUPPORT (LWIP_IPV6) -#endif - -/** - * PPP_NOTIFY_PHASE==1: Support PPP notify phase support - * - * PPP notify phase support allows you to set a callback which is - * called on change of the internal PPP state machine. - * - * This can be used for example to set a LED pattern depending on the - * current phase of the PPP session. - */ -#ifndef PPP_NOTIFY_PHASE -#define PPP_NOTIFY_PHASE 0 -#endif - -/** - * pbuf_type PPP is using for LCP, PAP, CHAP, EAP, CCP, IPCP and IP6CP packets. - * - * Memory allocated must be single buffered for PPP to works, it requires pbuf - * that are not going to be chained when allocated. This requires setting - * PBUF_POOL_BUFSIZE to at least 512 bytes, which is quite huge for small systems. - * - * Setting PPP_USE_PBUF_RAM to 1 makes PPP use memory from heap where continuous - * buffers are required, allowing you to use a smaller PBUF_POOL_BUFSIZE. - */ -#ifndef PPP_USE_PBUF_RAM -#define PPP_USE_PBUF_RAM 0 -#endif - -/** - * PPP_FCS_TABLE: Keep a 256*2 byte table to speed up FCS calculation for PPPoS - */ -#ifndef PPP_FCS_TABLE -#define PPP_FCS_TABLE 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. - */ -#ifndef MSCHAP_SUPPORT -#define MSCHAP_SUPPORT 0 -#endif -#if MSCHAP_SUPPORT -/* MSCHAP requires CHAP support */ -#undef CHAP_SUPPORT -#define CHAP_SUPPORT 1 -#endif /* MSCHAP_SUPPORT */ - -/** - * EAP_SUPPORT==1: Support EAP. - */ -#ifndef EAP_SUPPORT -#define EAP_SUPPORT 0 -#endif - -/** - * CCP_SUPPORT==1: Support CCP. - */ -#ifndef CCP_SUPPORT -#define CCP_SUPPORT 0 -#endif - -/** - * MPPE_SUPPORT==1: Support MPPE. - */ -#ifndef MPPE_SUPPORT -#define MPPE_SUPPORT 0 -#endif -#if MPPE_SUPPORT -/* MPPE requires CCP support */ -#undef CCP_SUPPORT -#define CCP_SUPPORT 1 -/* MPPE requires MSCHAP support */ -#undef MSCHAP_SUPPORT -#define MSCHAP_SUPPORT 1 -/* MSCHAP requires CHAP support */ -#undef CHAP_SUPPORT -#define CHAP_SUPPORT 1 -#endif /* MPPE_SUPPORT */ - -/** - * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! - */ -#ifndef CBCP_SUPPORT -#define CBCP_SUPPORT 0 -#endif - -/** - * ECP_SUPPORT==1: Support ECP. CURRENTLY NOT SUPPORTED! DO NOT SET! - */ -#ifndef ECP_SUPPORT -#define ECP_SUPPORT 0 -#endif - -/** - * DEMAND_SUPPORT==1: Support dial on demand. CURRENTLY NOT SUPPORTED! DO NOT SET! - */ -#ifndef DEMAND_SUPPORT -#define DEMAND_SUPPORT 0 -#endif - -/** - * LQR_SUPPORT==1: Support Link Quality Report. Do nothing except exchanging some LCP packets. - */ -#ifndef LQR_SUPPORT -#define LQR_SUPPORT 0 -#endif - -/** - * PPP_SERVER==1: Enable PPP server support (waiting for incoming PPP session). - * - * Currently only supported for PPPoS. - */ -#ifndef PPP_SERVER -#define PPP_SERVER 0 -#endif - -#if PPP_SERVER -/* - * PPP_OUR_NAME: Our name for authentication purposes - */ -#ifndef PPP_OUR_NAME -#define PPP_OUR_NAME "lwIP" -#endif -#endif /* PPP_SERVER */ - -/** - * VJ_SUPPORT==1: Support VJ header compression. - */ -#ifndef VJ_SUPPORT -#define VJ_SUPPORT 1 -#endif -/* VJ compression is only supported for TCP over IPv4 over PPPoS. */ -#if !PPPOS_SUPPORT || !PPP_IPV4_SUPPORT || !LWIP_TCP -#undef VJ_SUPPORT -#define VJ_SUPPORT 0 -#endif /* !PPPOS_SUPPORT */ - -/** - * PPP_MD5_RANDM==1: Use MD5 for better randomness. - * Enabled by default if CHAP, EAP, or L2TP AUTH support is enabled. - */ -#ifndef PPP_MD5_RANDM -#define PPP_MD5_RANDM (CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT) -#endif - -/** - * PolarSSL embedded library - * - * - * lwIP contains some files fetched from the latest BSD release of - * the PolarSSL project (PolarSSL 0.10.1-bsd) for ciphers and encryption - * methods we need for lwIP PPP support. - * - * The PolarSSL files were cleaned to contain only the necessary struct - * fields and functions needed for lwIP. - * - * The PolarSSL API was not changed at all, so if you are already using - * PolarSSL you can choose to skip the compilation of the included PolarSSL - * library into lwIP. - * - * If you are not using the embedded copy you must include external - * libraries into your arch/cc.h port file. - * - * Beware of the stack requirements which can be a lot larger if you are not - * using our cleaned PolarSSL library. - */ - -/** - * LWIP_USE_EXTERNAL_POLARSSL: Use external PolarSSL library - */ -#ifndef LWIP_USE_EXTERNAL_POLARSSL -#define LWIP_USE_EXTERNAL_POLARSSL 0 -#endif - -/** - * LWIP_USE_EXTERNAL_MBEDTLS: Use external mbed TLS library - */ -#ifndef LWIP_USE_EXTERNAL_MBEDTLS -#define LWIP_USE_EXTERNAL_MBEDTLS 0 -#endif - -/* - * PPP Timeouts - */ - -/** - * FSM_DEFTIMEOUT: Timeout time in seconds - */ -#ifndef FSM_DEFTIMEOUT -#define FSM_DEFTIMEOUT 6 -#endif - -/** - * FSM_DEFMAXTERMREQS: Maximum Terminate-Request transmissions - */ -#ifndef FSM_DEFMAXTERMREQS -#define FSM_DEFMAXTERMREQS 2 -#endif - -/** - * FSM_DEFMAXCONFREQS: Maximum Configure-Request transmissions - */ -#ifndef FSM_DEFMAXCONFREQS -#define FSM_DEFMAXCONFREQS 10 -#endif - -/** - * FSM_DEFMAXNAKLOOPS: Maximum number of nak loops - */ -#ifndef FSM_DEFMAXNAKLOOPS -#define FSM_DEFMAXNAKLOOPS 5 -#endif - -/** - * UPAP_DEFTIMEOUT: Timeout (seconds) for retransmitting req - */ -#ifndef UPAP_DEFTIMEOUT -#define UPAP_DEFTIMEOUT 6 -#endif - -/** - * UPAP_DEFTRANSMITS: Maximum number of auth-reqs to send - */ -#ifndef UPAP_DEFTRANSMITS -#define UPAP_DEFTRANSMITS 10 -#endif - -#if PPP_SERVER -/** - * UPAP_DEFREQTIME: Time to wait for auth-req from peer - */ -#ifndef UPAP_DEFREQTIME -#define UPAP_DEFREQTIME 30 -#endif -#endif /* PPP_SERVER */ - -/** - * CHAP_DEFTIMEOUT: Timeout (seconds) for retransmitting req - */ -#ifndef CHAP_DEFTIMEOUT -#define CHAP_DEFTIMEOUT 6 -#endif - -/** - * CHAP_DEFTRANSMITS: max # times to send challenge - */ -#ifndef CHAP_DEFTRANSMITS -#define CHAP_DEFTRANSMITS 10 -#endif - -#if PPP_SERVER -/** - * CHAP_DEFRECHALLENGETIME: If this option is > 0, rechallenge the peer every n seconds - */ -#ifndef CHAP_DEFRECHALLENGETIME -#define CHAP_DEFRECHALLENGETIME 0 -#endif -#endif /* PPP_SERVER */ - -/** - * EAP_DEFREQTIME: Time to wait for peer request - */ -#ifndef EAP_DEFREQTIME -#define EAP_DEFREQTIME 6 -#endif - -/** - * EAP_DEFALLOWREQ: max # times to accept requests - */ -#ifndef EAP_DEFALLOWREQ -#define EAP_DEFALLOWREQ 10 -#endif - -#if PPP_SERVER -/** - * EAP_DEFTIMEOUT: Timeout (seconds) for rexmit - */ -#ifndef EAP_DEFTIMEOUT -#define EAP_DEFTIMEOUT 6 -#endif - -/** - * EAP_DEFTRANSMITS: max # times to transmit - */ -#ifndef EAP_DEFTRANSMITS -#define EAP_DEFTRANSMITS 10 -#endif -#endif /* PPP_SERVER */ - -/** - * LCP_DEFLOOPBACKFAIL: Default number of times we receive our magic number from the peer - * before deciding the link is looped-back. - */ -#ifndef LCP_DEFLOOPBACKFAIL -#define LCP_DEFLOOPBACKFAIL 10 -#endif - -/** - * LCP_ECHOINTERVAL: Interval in seconds between keepalive echo requests, 0 to disable. - */ -#ifndef LCP_ECHOINTERVAL -#define LCP_ECHOINTERVAL 0 -#endif - -/** - * LCP_MAXECHOFAILS: Number of unanswered echo requests before failure. - */ -#ifndef LCP_MAXECHOFAILS -#define LCP_MAXECHOFAILS 3 -#endif - -/** - * PPP_MAXIDLEFLAG: Max Xmit idle time (in ms) before resend flag char. - */ -#ifndef PPP_MAXIDLEFLAG -#define PPP_MAXIDLEFLAG 100 -#endif - -/** - * PPP Packet sizes - */ - -/** - * PPP_MRU: Default MRU - */ -#ifndef PPP_MRU -#define PPP_MRU 1500 -#endif - -/** - * PPP_DEFMRU: Default MRU to try - */ -#ifndef PPP_DEFMRU -#define PPP_DEFMRU 1500 -#endif - -/** - * PPP_MAXMRU: Normally limit MRU to this (pppd default = 16384) - */ -#ifndef PPP_MAXMRU -#define PPP_MAXMRU 1500 -#endif - -/** - * PPP_MINMRU: No MRUs below this - */ -#ifndef PPP_MINMRU -#define PPP_MINMRU 128 -#endif - -/** - * PPPOL2TP_DEFMRU: Default MTU and MRU for L2TP - * Default = 1500 - PPPoE(6) - PPP Protocol(2) - IPv4 header(20) - UDP Header(8) - * - L2TP Header(6) - HDLC Header(2) - PPP Protocol(2) - MPPE Header(2) - PPP Protocol(2) - */ -#if PPPOL2TP_SUPPORT -#ifndef PPPOL2TP_DEFMRU -#define PPPOL2TP_DEFMRU 1450 -#endif -#endif /* PPPOL2TP_SUPPORT */ - -/** - * MAXNAMELEN: max length of hostname or name for auth - */ -#ifndef MAXNAMELEN -#define MAXNAMELEN 256 -#endif - -/** - * MAXSECRETLEN: max length of password or secret - */ -#ifndef MAXSECRETLEN -#define MAXSECRETLEN 256 -#endif - -/* ------------------------------------------------------------------------- */ - -/* - * Build triggers for embedded PolarSSL - */ -#if !LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS - -/* CHAP, EAP, L2TP AUTH and MD5 Random require MD5 support */ -#if CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT || PPP_MD5_RANDM -#define LWIP_INCLUDED_POLARSSL_MD5 1 -#endif /* CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT || PPP_MD5_RANDM */ - -#if MSCHAP_SUPPORT - -/* MSCHAP require MD4 support */ -#define LWIP_INCLUDED_POLARSSL_MD4 1 -/* MSCHAP require SHA1 support */ -#define LWIP_INCLUDED_POLARSSL_SHA1 1 -/* MSCHAP require DES support */ -#define LWIP_INCLUDED_POLARSSL_DES 1 - -/* MS-CHAP support is required for MPPE */ -#if MPPE_SUPPORT -/* MPPE require ARC4 support */ -#define LWIP_INCLUDED_POLARSSL_ARC4 1 -#endif /* MPPE_SUPPORT */ - -#endif /* MSCHAP_SUPPORT */ - -#endif /* !LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS */ - -/* Default value if unset */ -#ifndef LWIP_INCLUDED_POLARSSL_MD4 -#define LWIP_INCLUDED_POLARSSL_MD4 0 -#endif /* LWIP_INCLUDED_POLARSSL_MD4 */ -#ifndef LWIP_INCLUDED_POLARSSL_MD5 -#define LWIP_INCLUDED_POLARSSL_MD5 0 -#endif /* LWIP_INCLUDED_POLARSSL_MD5 */ -#ifndef LWIP_INCLUDED_POLARSSL_SHA1 -#define LWIP_INCLUDED_POLARSSL_SHA1 0 -#endif /* LWIP_INCLUDED_POLARSSL_SHA1 */ -#ifndef LWIP_INCLUDED_POLARSSL_DES -#define LWIP_INCLUDED_POLARSSL_DES 0 -#endif /* LWIP_INCLUDED_POLARSSL_DES */ -#ifndef LWIP_INCLUDED_POLARSSL_ARC4 -#define LWIP_INCLUDED_POLARSSL_ARC4 0 -#endif /* LWIP_INCLUDED_POLARSSL_ARC4 */ - -#endif /* PPP_SUPPORT */ - -/* Default value if unset */ -#ifndef PPP_NUM_TIMEOUTS -#define PPP_NUM_TIMEOUTS 0 -#endif /* PPP_NUM_TIMEOUTS */ - -#endif /* LWIP_PPP_OPTS_H */ diff --git a/core/c/include/netif/ppp/pppapi.h b/core/c/include/netif/ppp/pppapi.h deleted file mode 100755 index 70c262a..0000000 --- a/core/c/include/netif/ppp/pppapi.h +++ /dev/null @@ -1,137 +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_PPPAPI_H -#define LWIP_PPPAPI_H - -#include "netif/ppp/ppp_opts.h" - -#if LWIP_PPP_API /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/sys.h" -#include "lwip/netif.h" -#include "lwip/priv/tcpip_priv.h" -#include "netif/ppp/ppp.h" -#if PPPOS_SUPPORT -#include "netif/ppp/pppos.h" -#endif /* PPPOS_SUPPORT */ - -#ifdef __cplusplus -extern "C" { -#endif - -struct pppapi_msg_msg { - ppp_pcb *ppp; - union { -#if PPP_NOTIFY_PHASE - struct { - ppp_notify_phase_cb_fn notify_phase_cb; - } setnotifyphasecb; -#endif /* PPP_NOTIFY_PHASE */ -#if PPPOS_SUPPORT - struct { - struct netif *pppif; - pppos_output_cb_fn output_cb; - ppp_link_status_cb_fn link_status_cb; - void *ctx_cb; - } serialcreate; -#endif /* PPPOS_SUPPORT */ -#if PPPOE_SUPPORT - struct { - struct netif *pppif; - struct netif *ethif; - const char *service_name; - const char *concentrator_name; - ppp_link_status_cb_fn link_status_cb; - void *ctx_cb; - } ethernetcreate; -#endif /* PPPOE_SUPPORT */ -#if PPPOL2TP_SUPPORT - struct { - struct netif *pppif; - struct netif *netif; - API_MSG_M_DEF_C(ip_addr_t, ipaddr); - u16_t port; -#if PPPOL2TP_AUTH_SUPPORT - const u8_t *secret; - u8_t secret_len; -#endif /* PPPOL2TP_AUTH_SUPPORT */ - ppp_link_status_cb_fn link_status_cb; - void *ctx_cb; - } l2tpcreate; -#endif /* PPPOL2TP_SUPPORT */ - struct { - u16_t holdoff; - } connect; - struct { - u8_t nocarrier; - } close; - struct { - u8_t cmd; - void *arg; - } ioctl; - } msg; -}; - -struct pppapi_msg { - struct tcpip_api_call_data call; - struct pppapi_msg_msg msg; -}; - -/* API for application */ -err_t pppapi_set_default(ppp_pcb *pcb); -#if PPP_NOTIFY_PHASE -err_t pppapi_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb); -#endif /* PPP_NOTIFY_PHASE */ -#if PPPOS_SUPPORT -ppp_pcb *pppapi_pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, ppp_link_status_cb_fn link_status_cb, void *ctx_cb); -#endif /* PPPOS_SUPPORT */ -#if PPPOE_SUPPORT -ppp_pcb *pppapi_pppoe_create(struct netif *pppif, struct netif *ethif, const char *service_name, - const char *concentrator_name, ppp_link_status_cb_fn link_status_cb, - void *ctx_cb); -#endif /* PPPOE_SUPPORT */ -#if PPPOL2TP_SUPPORT -ppp_pcb *pppapi_pppol2tp_create(struct netif *pppif, struct netif *netif, ip_addr_t *ipaddr, u16_t port, - const u8_t *secret, u8_t secret_len, - ppp_link_status_cb_fn link_status_cb, void *ctx_cb); -#endif /* PPPOL2TP_SUPPORT */ -err_t pppapi_connect(ppp_pcb *pcb, u16_t holdoff); -#if PPP_SERVER -err_t pppapi_listen(ppp_pcb *pcb); -#endif /* PPP_SERVER */ -err_t pppapi_close(ppp_pcb *pcb, u8_t nocarrier); -err_t pppapi_free(ppp_pcb *pcb); -err_t pppapi_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_PPP_API */ - -#endif /* LWIP_PPPAPI_H */ diff --git a/core/c/include/netif/ppp/pppcrypt.h b/core/c/include/netif/ppp/pppcrypt.h deleted file mode 100755 index 968e532..0000000 --- a/core/c/include/netif/ppp/pppcrypt.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * pppcrypt.c - PPP/DES linkage for MS-CHAP and EAP SRP-SHA1 - * - * Extracted from chap_ms.c by James Carlson. - * - * Copyright (c) 1995 Eric Rosenquist. 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(s) of the authors of this software must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -/* This header file is included in all PPP modules needing hashes and/or ciphers */ - -#ifndef PPPCRYPT_H -#define PPPCRYPT_H - -/* - * If included PolarSSL copy is not used, user is expected to include - * external libraries in arch/cc.h (which is included by lwip/arch.h). - */ -#include "lwip/arch.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Map hashes and ciphers functions to PolarSSL - */ -#if !LWIP_USE_EXTERNAL_MBEDTLS - -#include "netif/ppp/polarssl/md4.h" -#define lwip_md4_context md4_context -#define lwip_md4_init(context) -#define lwip_md4_starts md4_starts -#define lwip_md4_update md4_update -#define lwip_md4_finish md4_finish -#define lwip_md4_free(context) - -#include "netif/ppp/polarssl/md5.h" -#define lwip_md5_context md5_context -#define lwip_md5_init(context) -#define lwip_md5_starts md5_starts -#define lwip_md5_update md5_update -#define lwip_md5_finish md5_finish -#define lwip_md5_free(context) - -#include "netif/ppp/polarssl/sha1.h" -#define lwip_sha1_context sha1_context -#define lwip_sha1_init(context) -#define lwip_sha1_starts sha1_starts -#define lwip_sha1_update sha1_update -#define lwip_sha1_finish sha1_finish -#define lwip_sha1_free(context) - -#include "netif/ppp/polarssl/des.h" -#define lwip_des_context des_context -#define lwip_des_init(context) -#define lwip_des_setkey_enc des_setkey_enc -#define lwip_des_crypt_ecb des_crypt_ecb -#define lwip_des_free(context) - -#include "netif/ppp/polarssl/arc4.h" -#define lwip_arc4_context arc4_context -#define lwip_arc4_init(context) -#define lwip_arc4_setup arc4_setup -#define lwip_arc4_crypt arc4_crypt -#define lwip_arc4_free(context) - -#endif /* !LWIP_USE_EXTERNAL_MBEDTLS */ - -/* - * Map hashes and ciphers functions to mbed TLS - */ -#if LWIP_USE_EXTERNAL_MBEDTLS - -#define lwip_md4_context mbedtls_md4_context -#define lwip_md4_init mbedtls_md4_init -#define lwip_md4_starts mbedtls_md4_starts -#define lwip_md4_update mbedtls_md4_update -#define lwip_md4_finish mbedtls_md4_finish -#define lwip_md4_free mbedtls_md4_free - -#define lwip_md5_context mbedtls_md5_context -#define lwip_md5_init mbedtls_md5_init -#define lwip_md5_starts mbedtls_md5_starts -#define lwip_md5_update mbedtls_md5_update -#define lwip_md5_finish mbedtls_md5_finish -#define lwip_md5_free mbedtls_md5_free - -#define lwip_sha1_context mbedtls_sha1_context -#define lwip_sha1_init mbedtls_sha1_init -#define lwip_sha1_starts mbedtls_sha1_starts -#define lwip_sha1_update mbedtls_sha1_update -#define lwip_sha1_finish mbedtls_sha1_finish -#define lwip_sha1_free mbedtls_sha1_free - -#define lwip_des_context mbedtls_des_context -#define lwip_des_init mbedtls_des_init -#define lwip_des_setkey_enc mbedtls_des_setkey_enc -#define lwip_des_crypt_ecb mbedtls_des_crypt_ecb -#define lwip_des_free mbedtls_des_free - -#define lwip_arc4_context mbedtls_arc4_context -#define lwip_arc4_init mbedtls_arc4_init -#define lwip_arc4_setup mbedtls_arc4_setup -#define lwip_arc4_crypt(context, buffer, length) mbedtls_arc4_crypt(context, length, buffer, buffer) -#define lwip_arc4_free mbedtls_arc4_free - -#endif /* LWIP_USE_EXTERNAL_MBEDTLS */ - -void pppcrypt_56_to_64_bit_key(u_char *key, u_char *des_key); - -#ifdef __cplusplus -} -#endif - -#endif /* PPPCRYPT_H */ - -#endif /* PPP_SUPPORT */ diff --git a/core/c/include/netif/ppp/pppdebug.h b/core/c/include/netif/ppp/pppdebug.h deleted file mode 100755 index 391b7c6..0000000 --- a/core/c/include/netif/ppp/pppdebug.h +++ /dev/null @@ -1,88 +0,0 @@ -/***************************************************************************** -* pppdebug.h - System debugging utilities. -* -* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. -* portions Copyright (c) 1998 Global Election Systems Inc. -* portions Copyright (c) 2001 by Cognizant Pty Ltd. -* -* 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 (please don't use tabs!) -* -* 03-01-01 Marc Boucher -* Ported to lwIP. -* 98-07-29 Guy Lancaster , Global Election Systems Inc. -* Original. -* -***************************************************************************** -*/ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef PPPDEBUG_H -#define PPPDEBUG_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Trace levels. */ -#define LOG_CRITICAL (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE) -#define LOG_ERR (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE) -#define LOG_NOTICE (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING) -#define LOG_WARNING (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING) -#define LOG_INFO (PPP_DEBUG) -#define LOG_DETAIL (PPP_DEBUG) -#define LOG_DEBUG (PPP_DEBUG) - -#if PPP_DEBUG - -#define MAINDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) -#define SYSDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) -#define FSMDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) -#define LCPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) -#define IPCPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) -#define IPV6CPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) -#define UPAPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) -#define CHAPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) -#define PPPDEBUG(a, b) LWIP_DEBUGF(a, b) - -#else /* PPP_DEBUG */ - -#define MAINDEBUG(a) -#define SYSDEBUG(a) -#define FSMDEBUG(a) -#define LCPDEBUG(a) -#define IPCPDEBUG(a) -#define IPV6CPDEBUG(a) -#define UPAPDEBUG(a) -#define CHAPDEBUG(a) -#define PPPDEBUG(a, b) - -#endif /* PPP_DEBUG */ - -#ifdef __cplusplus -} -#endif - -#endif /* PPPDEBUG_H */ - -#endif /* PPP_SUPPORT */ diff --git a/core/c/include/netif/ppp/pppoe.h b/core/c/include/netif/ppp/pppoe.h deleted file mode 100755 index 93acd4c..0000000 --- a/core/c/include/netif/ppp/pppoe.h +++ /dev/null @@ -1,187 +0,0 @@ -/***************************************************************************** -* pppoe.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. - */ -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef PPP_OE_H -#define PPP_OE_H - -#include "ppp.h" -#include "lwip/etharp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct pppoehdr { - PACK_STRUCT_FLD_8(u8_t vertype); - PACK_STRUCT_FLD_8(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 -/* 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 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 */ - ppp_pcb *pcb; /* PPP PCB */ - - struct eth_addr sc_dest; /* hardware address of concentrator */ - u16_t sc_session; /* PPPoE session id */ - u8_t sc_state; /* discovery phase or session connected */ - -#ifdef PPPOE_TODO - u8_t *sc_service_name; /* if != NULL: requested name of service */ - u8_t *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 */ - u8_t sc_ac_cookie_len; /* length of cookie data */ -#ifdef PPPOE_SERVER - u8_t *sc_hunique; /* content of host unique we must echo back */ - u8_t sc_hunique_len; /* length of host unique */ -#endif - u8_t sc_padi_retried; /* number of PADI retries already done */ - u8_t sc_padr_retried; /* number of PADR retries already done */ -}; - - -#define pppoe_init() /* compatibility define, no initialization needed */ - -ppp_pcb *pppoe_create(struct netif *pppif, - struct netif *ethif, - const char *service_name, const char *concentrator_name, - ppp_link_status_cb_fn link_status_cb, void *ctx_cb); - -/* - * Functions called from lwIP - * DO NOT CALL FROM lwIP USER APPLICATION. - */ -void pppoe_disc_input(struct netif *netif, struct pbuf *p); -void pppoe_data_input(struct netif *netif, struct pbuf *p); - -#ifdef __cplusplus -} -#endif - -#endif /* PPP_OE_H */ - -#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ diff --git a/core/c/include/netif/ppp/pppol2tp.h b/core/c/include/netif/ppp/pppol2tp.h deleted file mode 100755 index e09d6e1..0000000 --- a/core/c/include/netif/ppp/pppol2tp.h +++ /dev/null @@ -1,209 +0,0 @@ -/** - * @file - * Network Point to Point Protocol over Layer 2 Tunneling Protocol header file. - * - */ - -/* - * 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 "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && PPPOL2TP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef PPPOL2TP_H -#define PPPOL2TP_H - -#include "ppp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Timeout */ -#define PPPOL2TP_CONTROL_TIMEOUT (5*1000) /* base for quick timeout calculation */ -#define PPPOL2TP_SLOW_RETRY (60*1000) /* persistent retry interval */ - -#define PPPOL2TP_MAXSCCRQ 4 /* retry SCCRQ four times (quickly) */ -#define PPPOL2TP_MAXICRQ 4 /* retry IRCQ four times */ -#define PPPOL2TP_MAXICCN 4 /* retry ICCN four times */ - -/* L2TP header flags */ -#define PPPOL2TP_HEADERFLAG_CONTROL 0x8000 -#define PPPOL2TP_HEADERFLAG_LENGTH 0x4000 -#define PPPOL2TP_HEADERFLAG_SEQUENCE 0x0800 -#define PPPOL2TP_HEADERFLAG_OFFSET 0x0200 -#define PPPOL2TP_HEADERFLAG_PRIORITY 0x0100 -#define PPPOL2TP_HEADERFLAG_VERSION 0x0002 - -/* Mandatory bits for control: Control, Length, Sequence, Version 2 */ -#define PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY (PPPOL2TP_HEADERFLAG_CONTROL|PPPOL2TP_HEADERFLAG_LENGTH|PPPOL2TP_HEADERFLAG_SEQUENCE|PPPOL2TP_HEADERFLAG_VERSION) -/* Forbidden bits for control: Offset, Priority */ -#define PPPOL2TP_HEADERFLAG_CONTROL_FORBIDDEN (PPPOL2TP_HEADERFLAG_OFFSET|PPPOL2TP_HEADERFLAG_PRIORITY) - -/* Mandatory bits for data: Version 2 */ -#define PPPOL2TP_HEADERFLAG_DATA_MANDATORY (PPPOL2TP_HEADERFLAG_VERSION) - -/* AVP (Attribute Value Pair) header */ -#define PPPOL2TP_AVPHEADERFLAG_MANDATORY 0x8000 -#define PPPOL2TP_AVPHEADERFLAG_HIDDEN 0x4000 -#define PPPOL2TP_AVPHEADERFLAG_LENGTHMASK 0x03ff - -/* -- AVP - Message type */ -#define PPPOL2TP_AVPTYPE_MESSAGE 0 /* Message type */ - -/* Control Connection Management */ -#define PPPOL2TP_MESSAGETYPE_SCCRQ 1 /* Start Control Connection Request */ -#define PPPOL2TP_MESSAGETYPE_SCCRP 2 /* Start Control Connection Reply */ -#define PPPOL2TP_MESSAGETYPE_SCCCN 3 /* Start Control Connection Connected */ -#define PPPOL2TP_MESSAGETYPE_STOPCCN 4 /* Stop Control Connection Notification */ -#define PPPOL2TP_MESSAGETYPE_HELLO 6 /* Hello */ -/* Call Management */ -#define PPPOL2TP_MESSAGETYPE_OCRQ 7 /* Outgoing Call Request */ -#define PPPOL2TP_MESSAGETYPE_OCRP 8 /* Outgoing Call Reply */ -#define PPPOL2TP_MESSAGETYPE_OCCN 9 /* Outgoing Call Connected */ -#define PPPOL2TP_MESSAGETYPE_ICRQ 10 /* Incoming Call Request */ -#define PPPOL2TP_MESSAGETYPE_ICRP 11 /* Incoming Call Reply */ -#define PPPOL2TP_MESSAGETYPE_ICCN 12 /* Incoming Call Connected */ -#define PPPOL2TP_MESSAGETYPE_CDN 14 /* Call Disconnect Notify */ -/* Error reporting */ -#define PPPOL2TP_MESSAGETYPE_WEN 15 /* WAN Error Notify */ -/* PPP Session Control */ -#define PPPOL2TP_MESSAGETYPE_SLI 16 /* Set Link Info */ - -/* -- AVP - Result code */ -#define PPPOL2TP_AVPTYPE_RESULTCODE 1 /* Result code */ -#define PPPOL2TP_RESULTCODE 1 /* General request to clear control connection */ - -/* -- AVP - Protocol version (!= L2TP Header version) */ -#define PPPOL2TP_AVPTYPE_VERSION 2 -#define PPPOL2TP_VERSION 0x0100 /* L2TP Protocol version 1, revision 0 */ - -/* -- AVP - Framing capabilities */ -#define PPPOL2TP_AVPTYPE_FRAMINGCAPABILITIES 3 /* Bearer capabilities */ -#define PPPOL2TP_FRAMINGCAPABILITIES 0x00000003 /* Async + Sync framing */ - -/* -- AVP - Bearer capabilities */ -#define PPPOL2TP_AVPTYPE_BEARERCAPABILITIES 4 /* Bearer capabilities */ -#define PPPOL2TP_BEARERCAPABILITIES 0x00000003 /* Analog + Digital Access */ - -/* -- AVP - Tie breaker */ -#define PPPOL2TP_AVPTYPE_TIEBREAKER 5 - -/* -- AVP - Host name */ -#define PPPOL2TP_AVPTYPE_HOSTNAME 7 /* Host name */ -#define PPPOL2TP_HOSTNAME "lwIP" /* FIXME: make it configurable */ - -/* -- AVP - Vendor name */ -#define PPPOL2TP_AVPTYPE_VENDORNAME 8 /* Vendor name */ -#define PPPOL2TP_VENDORNAME "lwIP" /* FIXME: make it configurable */ - -/* -- AVP - Assign tunnel ID */ -#define PPPOL2TP_AVPTYPE_TUNNELID 9 /* Assign Tunnel ID */ - -/* -- AVP - Receive window size */ -#define PPPOL2TP_AVPTYPE_RECEIVEWINDOWSIZE 10 /* Receive window size */ -#define PPPOL2TP_RECEIVEWINDOWSIZE 8 /* FIXME: make it configurable */ - -/* -- AVP - Challenge */ -#define PPPOL2TP_AVPTYPE_CHALLENGE 11 /* Challenge */ - -/* -- AVP - Cause code */ -#define PPPOL2TP_AVPTYPE_CAUSECODE 12 /* Cause code*/ - -/* -- AVP - Challenge response */ -#define PPPOL2TP_AVPTYPE_CHALLENGERESPONSE 13 /* Challenge response */ -#define PPPOL2TP_AVPTYPE_CHALLENGERESPONSE_SIZE 16 - -/* -- AVP - Assign session ID */ -#define PPPOL2TP_AVPTYPE_SESSIONID 14 /* Assign Session ID */ - -/* -- AVP - Call serial number */ -#define PPPOL2TP_AVPTYPE_CALLSERIALNUMBER 15 /* Call Serial Number */ - -/* -- AVP - Framing type */ -#define PPPOL2TP_AVPTYPE_FRAMINGTYPE 19 /* Framing Type */ -#define PPPOL2TP_FRAMINGTYPE 0x00000001 /* Sync framing */ - -/* -- AVP - TX Connect Speed */ -#define PPPOL2TP_AVPTYPE_TXCONNECTSPEED 24 /* TX Connect Speed */ -#define PPPOL2TP_TXCONNECTSPEED 100000000 /* Connect speed: 100 Mbits/s */ - -/* L2TP Session state */ -#define PPPOL2TP_STATE_INITIAL 0 -#define PPPOL2TP_STATE_SCCRQ_SENT 1 -#define PPPOL2TP_STATE_ICRQ_SENT 2 -#define PPPOL2TP_STATE_ICCN_SENT 3 -#define PPPOL2TP_STATE_DATA 4 - -#define PPPOL2TP_OUTPUT_DATA_HEADER_LEN 6 /* Our data header len */ - -/* - * PPPoL2TP interface control block. - */ -typedef struct pppol2tp_pcb_s pppol2tp_pcb; -struct pppol2tp_pcb_s { - ppp_pcb *ppp; /* PPP PCB */ - u8_t phase; /* L2TP phase */ - struct udp_pcb *udp; /* UDP L2TP Socket */ - struct netif *netif; /* Output interface, used as a default route */ - ip_addr_t remote_ip; /* LNS IP Address */ - u16_t remote_port; /* LNS port */ -#if PPPOL2TP_AUTH_SUPPORT - const u8_t *secret; /* Secret string */ - u8_t secret_len; /* Secret string length */ - u8_t secret_rv[16]; /* Random vector */ - u8_t challenge_hash[16]; /* Challenge response */ - u8_t send_challenge; /* Boolean whether the next sent packet should contains a challenge response */ -#endif /* PPPOL2TP_AUTH_SUPPORT */ - - u16_t tunnel_port; /* Tunnel port */ - u16_t our_ns; /* NS to peer */ - u16_t peer_nr; /* NR from peer */ - u16_t peer_ns; /* Expected NS from peer */ - u16_t source_tunnel_id; /* Tunnel ID assigned by peer */ - u16_t remote_tunnel_id; /* Tunnel ID assigned to peer */ - u16_t source_session_id; /* Session ID assigned by peer */ - u16_t remote_session_id; /* Session ID assigned to peer */ - - u8_t sccrq_retried; /* number of SCCRQ retries already done */ - u8_t icrq_retried; /* number of ICRQ retries already done */ - u8_t iccn_retried; /* number of ICCN retries already done */ -}; - - -/* Create a new L2TP session. */ -ppp_pcb *pppol2tp_create(struct netif *pppif, - struct netif *netif, const ip_addr_t *ipaddr, u16_t port, - const u8_t *secret, u8_t secret_len, - ppp_link_status_cb_fn link_status_cb, void *ctx_cb); - -#ifdef __cplusplus -} -#endif - -#endif /* PPPOL2TP_H */ -#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/core/c/include/netif/ppp/pppos.h b/core/c/include/netif/ppp/pppos.h deleted file mode 100755 index acaedd7..0000000 --- a/core/c/include/netif/ppp/pppos.h +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @file - * Network Point to Point Protocol over Serial header file. - * - */ - -/* - * 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 "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef PPPOS_H -#define PPPOS_H - -#include "lwip/sys.h" - -#include "ppp.h" -#include "vj.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* PPP packet parser states. Current state indicates operation yet to be - * completed. */ -enum { - PDIDLE = 0, /* Idle state - waiting. */ - PDSTART, /* Process start flag. */ - PDADDRESS, /* Process address field. */ - PDCONTROL, /* Process control field. */ - PDPROTOCOL1, /* Process protocol field 1. */ - PDPROTOCOL2, /* Process protocol field 2. */ - PDDATA /* Process data byte. */ -}; - -/* PPPoS serial output callback function prototype */ -typedef u32_t (*pppos_output_cb_fn)(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx); - -/* - * Extended asyncmap - allows any character to be escaped. - */ -typedef u8_t ext_accm[32]; - -/* - * PPPoS interface control block. - */ -typedef struct pppos_pcb_s pppos_pcb; -struct pppos_pcb_s { - /* -- below are data that will NOT be cleared between two sessions */ - ppp_pcb *ppp; /* PPP PCB */ - pppos_output_cb_fn output_cb; /* PPP serial output callback */ - - /* -- below are data that will be cleared between two sessions - * - * last_xmit must be the first member of cleared members, because it is - * used to know which part must not be cleared. - */ - u32_t last_xmit; /* Time of last transmission. */ - ext_accm out_accm; /* Async-Ctl-Char-Map for output. */ - - /* flags */ - unsigned int open :1; /* Set if PPPoS is open */ - unsigned int pcomp :1; /* Does peer accept protocol compression? */ - unsigned int accomp :1; /* Does peer accept addr/ctl compression? */ - - /* PPPoS rx */ - ext_accm in_accm; /* Async-Ctl-Char-Map for input. */ - struct pbuf *in_head, *in_tail; /* The input packet. */ - u16_t in_protocol; /* The input protocol code. */ - u16_t in_fcs; /* Input Frame Check Sequence value. */ - u8_t in_state; /* The input process state. */ - u8_t in_escaped; /* Escape next character. */ -}; - -/* Create a new PPPoS session. */ -ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, - ppp_link_status_cb_fn link_status_cb, void *ctx_cb); - -#if !NO_SYS && !PPP_INPROC_IRQ_SAFE -/* Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread. */ -err_t pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l); -#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ - -/* PPP over Serial: this is the input function to be called for received data. */ -void pppos_input(ppp_pcb *ppp, u8_t* data, int len); - - -/* - * Functions called from lwIP - * DO NOT CALL FROM lwIP USER APPLICATION. - */ -#if !NO_SYS && !PPP_INPROC_IRQ_SAFE -err_t pppos_input_sys(struct pbuf *p, struct netif *inp); -#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ - -#ifdef __cplusplus -} -#endif - -#endif /* PPPOS_H */ -#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/core/c/include/netif/ppp/upap.h b/core/c/include/netif/ppp/upap.h deleted file mode 100755 index 8d90e35..0000000 --- a/core/c/include/netif/ppp/upap.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * upap.h - User/Password Authentication Protocol definitions. - * - * Copyright (c) 1984-2000 Carnegie Mellon University. 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 "Carnegie Mellon University" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For permission or any legal - * details, please contact - * Office of Technology Transfer - * Carnegie Mellon University - * 5000 Forbes Avenue - * Pittsburgh, PA 15213-3890 - * (412) 268-4387, fax: (412) 268-7395 - * tech-transfer@andrew.cmu.edu - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Computing Services - * at Carnegie Mellon University (http://www.cmu.edu/computing/)." - * - * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE - * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * $Id: upap.h,v 1.8 2002/12/04 23:03:33 paulus Exp $ - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef UPAP_H -#define UPAP_H - -#include "ppp.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Packet header = Code, id, length. - */ -#define UPAP_HEADERLEN 4 - - -/* - * UPAP codes. - */ -#define UPAP_AUTHREQ 1 /* Authenticate-Request */ -#define UPAP_AUTHACK 2 /* Authenticate-Ack */ -#define UPAP_AUTHNAK 3 /* Authenticate-Nak */ - - -/* - * Client states. - */ -#define UPAPCS_INITIAL 0 /* Connection down */ -#define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */ -#define UPAPCS_PENDING 2 /* Connection down, have requested auth */ -#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */ -#define UPAPCS_OPEN 4 /* We've received an Ack */ -#define UPAPCS_BADAUTH 5 /* We've received a Nak */ - -/* - * Server states. - */ -#define UPAPSS_INITIAL 0 /* Connection down */ -#define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */ -#define UPAPSS_PENDING 2 /* Connection down, have requested auth */ -#define UPAPSS_LISTEN 3 /* Listening for an Authenticate */ -#define UPAPSS_OPEN 4 /* We've sent an Ack */ -#define UPAPSS_BADAUTH 5 /* We've sent a Nak */ - - -/* - * Timeouts. - */ -#if 0 /* moved to ppp_opts.h */ -#define UPAP_DEFTIMEOUT 3 /* Timeout (seconds) for retransmitting req */ -#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ -#endif /* moved to ppp_opts.h */ - -/* - * Each interface is described by upap structure. - */ -#if PAP_SUPPORT -typedef struct upap_state { - const char *us_user; /* User */ - u8_t us_userlen; /* User length */ - const char *us_passwd; /* Password */ - u8_t us_passwdlen; /* Password length */ - u8_t us_clientstate; /* Client state */ -#if PPP_SERVER - u8_t us_serverstate; /* Server state */ -#endif /* PPP_SERVER */ - u8_t us_id; /* Current id */ - u8_t us_transmits; /* Number of auth-reqs sent */ -} upap_state; -#endif /* PAP_SUPPORT */ - - -void upap_authwithpeer(ppp_pcb *pcb, const char *user, const char *password); -#if PPP_SERVER -void upap_authpeer(ppp_pcb *pcb); -#endif /* PPP_SERVER */ - -extern const struct protent pap_protent; - -#ifdef __cplusplus -} -#endif - -#endif /* UPAP_H */ -#endif /* PPP_SUPPORT && PAP_SUPPORT */ diff --git a/core/c/include/netif/ppp/vj.h b/core/c/include/netif/ppp/vj.h deleted file mode 100755 index 1d91f25..0000000 --- a/core/c/include/netif/ppp/vj.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Definitions for tcp compression routines. - * - * $Id: vj.h,v 1.7 2010/02/22 17:52:09 goldsimon Exp $ - * - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: - * - Initial distribution. - */ - -#include "netif/ppp/ppp_opts.h" -#if PPP_SUPPORT && VJ_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#ifndef VJ_H -#define VJ_H - -#include "lwip/ip.h" -#include "lwip/priv/tcp_priv.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_SLOTS 16 /* must be > 2 and < 256 */ -#define MAX_HDR 128 - -/* - * Compressed packet format: - * - * The first octet contains the packet type (top 3 bits), TCP - * 'push' bit, and flags that indicate which of the 4 TCP sequence - * numbers have changed (bottom 5 bits). The next octet is a - * conversation number that associates a saved IP/TCP header with - * the compressed packet. The next two octets are the TCP checksum - * from the original datagram. The next 0 to 15 octets are - * sequence number changes, one change per bit set in the header - * (there may be no changes and there are two special cases where - * the receiver implicitly knows what changed -- see below). - * - * There are 5 numbers which can change (they are always inserted - * in the following order): TCP urgent pointer, window, - * acknowlegement, sequence number and IP ID. (The urgent pointer - * is different from the others in that its value is sent, not the - * change in value.) Since typical use of SLIP links is biased - * toward small packets (see comments on MTU/MSS below), changes - * use a variable length coding with one octet for numbers in the - * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the - * range 256 - 65535 or 0. (If the change in sequence number or - * ack is more than 65535, an uncompressed packet is sent.) - */ - -/* - * Packet types (must not conflict with IP protocol version) - * - * The top nibble of the first octet is the packet type. There are - * three possible types: IP (not proto TCP or tcp with one of the - * control flags set); uncompressed TCP (a normal IP/TCP packet but - * with the 8-bit protocol field replaced by an 8-bit connection id -- - * this type of packet syncs the sender & receiver); and compressed - * TCP (described above). - * - * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and - * is logically part of the 4-bit "changes" field that follows. Top - * three bits are actual packet type. For backward compatibility - * and in the interest of conserving bits, numbers are chosen so the - * IP protocol version number (4) which normally appears in this nibble - * means "IP packet". - */ - -/* packet types */ -#define TYPE_IP 0x40 -#define TYPE_UNCOMPRESSED_TCP 0x70 -#define TYPE_COMPRESSED_TCP 0x80 -#define TYPE_ERROR 0x00 - -/* Bits in first octet of compressed packet */ -#define NEW_C 0x40 /* flag bits for what changed in a packet */ -#define NEW_I 0x20 -#define NEW_S 0x08 -#define NEW_A 0x04 -#define NEW_W 0x02 -#define NEW_U 0x01 - -/* reserved, special-case values of above */ -#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ -#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ -#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) - -#define TCP_PUSH_BIT 0x10 - - -/* - * "state" data for each active tcp conversation on the wire. This is - * basically a copy of the entire IP/TCP header from the last packet - * we saw from the conversation together with a small identifier - * the transmit & receive ends of the line use to locate saved header. - */ -struct cstate { - struct cstate *cs_next; /* next most recently used state (xmit only) */ - u16_t cs_hlen; /* size of hdr (receive only) */ - u8_t cs_id; /* connection # associated with this state */ - u8_t cs_filler; - union { - char csu_hdr[MAX_HDR]; - struct ip_hdr csu_ip; /* ip/tcp hdr from most recent packet */ - } vjcs_u; -}; -#define cs_ip vjcs_u.csu_ip -#define cs_hdr vjcs_u.csu_hdr - - -struct vjstat { - u32_t vjs_packets; /* outbound packets */ - u32_t vjs_compressed; /* outbound compressed packets */ - u32_t vjs_searches; /* searches for connection state */ - u32_t vjs_misses; /* times couldn't find conn. state */ - u32_t vjs_uncompressedin; /* inbound uncompressed packets */ - u32_t vjs_compressedin; /* inbound compressed packets */ - u32_t vjs_errorin; /* inbound unknown type packets */ - u32_t vjs_tossed; /* inbound packets tossed because of error */ -}; - -/* - * all the state data for one serial line (we need one of these per line). - */ -struct vjcompress { - struct cstate *last_cs; /* most recently used tstate */ - u8_t last_recv; /* last rcvd conn. id */ - u8_t last_xmit; /* last sent conn. id */ - u16_t flags; - u8_t maxSlotIndex; - u8_t compressSlot; /* Flag indicating OK to compress slot ID. */ -#if LINK_STATS - struct vjstat stats; -#endif - struct cstate tstate[MAX_SLOTS]; /* xmit connection states */ - struct cstate rstate[MAX_SLOTS]; /* receive connection states */ -}; - -/* flag values */ -#define VJF_TOSS 1U /* tossing rcvd frames because of input err */ - -extern void vj_compress_init (struct vjcompress *comp); -extern u8_t vj_compress_tcp (struct vjcompress *comp, struct pbuf **pb); -extern void vj_uncompress_err (struct vjcompress *comp); -extern int vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp); -extern int vj_uncompress_tcp (struct pbuf **nb, struct vjcompress *comp); - -#ifdef __cplusplus -} -#endif - -#endif /* VJ_H */ - -#endif /* PPP_SUPPORT && VJ_SUPPORT */ diff --git a/core/c/include/netif/slipif.h b/core/c/include/netif/slipif.h deleted file mode 100755 index 4e68c94..0000000 --- a/core/c/include/netif/slipif.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @file - * - * SLIP netif API - */ - -/* - * 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 LWIP_HDR_NETIF_SLIPIF_H -#define LWIP_HDR_NETIF_SLIPIF_H - -#include "lwip/opt.h" -#include "lwip/netif.h" - -/** Set this to 1 to start a thread that blocks reading on the serial line - * (using sio_read()). - */ -#ifndef SLIP_USE_RX_THREAD -#define SLIP_USE_RX_THREAD !NO_SYS -#endif - -/** Set this to 1 to enable functions to pass in RX bytes from ISR context. - * If enabled, slipif_received_byte[s]() process incoming bytes and put assembled - * packets on a queue, which is fed into lwIP from slipif_poll(). - * If disabled, slipif_poll() polls the serial line (using sio_tryread()). - */ -#ifndef SLIP_RX_FROM_ISR -#define SLIP_RX_FROM_ISR 0 -#endif - -/** Set this to 1 (default for SLIP_RX_FROM_ISR) to queue incoming packets - * received by slipif_received_byte[s]() as long as PBUF_POOL pbufs are available. - * If disabled, packets will be dropped if more than one packet is received. - */ -#ifndef SLIP_RX_QUEUE -#define SLIP_RX_QUEUE SLIP_RX_FROM_ISR -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -err_t slipif_init(struct netif * netif); -void slipif_poll(struct netif *netif); -#if SLIP_RX_FROM_ISR -void slipif_process_rxqueue(struct netif *netif); -void slipif_received_byte(struct netif *netif, u8_t data); -void slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len); -#endif /* SLIP_RX_FROM_ISR */ - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_HDR_NETIF_SLIPIF_H */ - diff --git a/core/c/include/netif/zepif.h b/core/c/include/netif/zepif.h deleted file mode 100755 index 059c8b0..0000000 --- a/core/c/include/netif/zepif.h +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @file - * - * A netif implementing the ZigBee Eencapsulation Protocol (ZEP). - * This is used to tunnel 6LowPAN over UDP. - */ - -/* - * Copyright (c) 2018 Simon Goldschmidt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ - -#ifndef LWIP_HDR_ZEPIF_H -#define LWIP_HDR_ZEPIF_H - -#include "lwip/opt.h" -#include "netif/lowpan6.h" - -#if LWIP_IPV6 && LWIP_UDP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZEPIF_DEFAULT_UDP_PORT 17754 - -/** Pass this struct as 'state' to netif_add to control the behaviour - * of this netif. If NULL is passed, default behaviour is chosen */ -struct zepif_init { - /** The UDP port used to ZEP frames from (0 = default) */ - u16_t zep_src_udp_port; - /** The UDP port used to ZEP frames to (0 = default) */ - u16_t zep_dst_udp_port; - /** The IP address to sed ZEP frames from (NULL = ANY) */ - const ip_addr_t *zep_src_ip_addr; - /** The IP address to sed ZEP frames to (NULL = BROADCAST) */ - const ip_addr_t *zep_dst_ip_addr; - /** If != NULL, the udp pcb is bound to this netif */ - const struct netif *zep_netif; - /** MAC address of the 6LowPAN device */ - u8_t addr[6]; -}; - -err_t zepif_init(struct netif *netif); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6 && LWIP_UDP */ - -#endif /* LWIP_HDR_ZEPIF_H */ diff --git a/core/c/include/posix/errno.h b/core/c/include/posix/errno.h deleted file mode 100755 index 420f554..0000000 --- a/core/c/include/posix/errno.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file - * This file is a posix wrapper for lwip/errno.h. - */ - -/* - * 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/errno.h" diff --git a/core/c/include/posix/netdb.h b/core/c/include/posix/netdb.h deleted file mode 100755 index 29abbaf..0000000 --- a/core/c/include/posix/netdb.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file - * This file is a posix wrapper for lwip/netdb.h. - */ - -/* - * 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/netdb.h" diff --git a/core/c/include/posix/sys/socket.h b/core/c/include/posix/sys/socket.h deleted file mode 100755 index 68267e5..0000000 --- a/core/c/include/posix/sys/socket.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file - * This file is a posix wrapper for lwip/sockets.h. - */ - -/* - * 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/sockets.h" diff --git a/core/c_core.go b/core/c_core.go deleted file mode 100755 index cc21229..0000000 --- a/core/c_core.go +++ /dev/null @@ -1,22 +0,0 @@ -package core - -/* -#include "c/core/init.c" -#include "c/core/def.c" -#include "c/core/dns.c" -#include "c/core/inet_chksum.c" -#include "c/core/ip.c" -#include "c/core/mem.c" -#include "c/core/memp.c" -#include "c/core/netif.c" -#include "c/core/pbuf.c" -#include "c/core/raw.c" -#include "c/core/stats.c" -#include "c/core/sys.c" -#include "c/core/tcp.c" -#include "c/core/tcp_in.c" -#include "c/core/tcp_out.c" -#include "c/core/timeouts.c" -#include "c/core/udp.c" -*/ -import "C" diff --git a/core/c_core_4.go b/core/c_core_4.go deleted file mode 100755 index 98f4cda..0000000 --- a/core/c_core_4.go +++ /dev/null @@ -1,13 +0,0 @@ -package core - -/* -#include "c/core/ipv4/autoip.c" -#include "c/core/ipv4/dhcp.c" -#include "c/core/ipv4/etharp.c" -#include "c/core/ipv4/icmp.c" -#include "c/core/ipv4/igmp.c" -#include "c/core/ipv4/ip4_frag.c" -#include "c/core/ipv4/ip4.c" -#include "c/core/ipv4/ip4_addr.c" -*/ -import "C" diff --git a/core/c_core_6.go b/core/c_core_6.go deleted file mode 100755 index c8a6b7f..0000000 --- a/core/c_core_6.go +++ /dev/null @@ -1,14 +0,0 @@ -package core - -/* -#include "c/core/ipv6/dhcp6.c" -#include "c/core/ipv6/ethip6.c" -#include "c/core/ipv6/icmp6.c" -#include "c/core/ipv6/inet6.c" -#include "c/core/ipv6/ip6.c" -#include "c/core/ipv6/ip6_addr.c" -#include "c/core/ipv6/ip6_frag.c" -#include "c/core/ipv6/mld6.c" -#include "c/core/ipv6/nd6.c" -*/ -import "C" diff --git a/core/c_custom.go b/core/c_custom.go deleted file mode 100755 index f2aa106..0000000 --- a/core/c_custom.go +++ /dev/null @@ -1,7 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/custom -#include "c/custom/sys_arch.c" -*/ -import "C" diff --git a/core/conn.go b/core/conn.go deleted file mode 100755 index f25974c..0000000 --- a/core/conn.go +++ /dev/null @@ -1,82 +0,0 @@ -package core - -import ( - "net" - "time" -) - -// TCPConn abstracts a TCP connection comming from TUN. This connection -// should be handled by a registered TCP proxy handler. It's important -// to note that callback members are called from lwIP, they are already -// in the lwIP thread when they are called, that is, they are holding -// the lwipMutex. -type TCPConn interface { - // Sent will be called when sent data has been acknowledged by peer. - Sent(len uint16) error - - // Receive will be called when data arrives from TUN. - Receive(data []byte) error - - // Err will be called when a fatal error has occurred on the connection. - // The corresponding pcb is already freed when this callback is called - Err(err error) - - // LocalClosed will be called when lwIP receives a FIN segment on a - // connection. - LocalClosed() error - - // Poll will be periodically called by TCP timers. - Poll() error - - // RemoteAddr returns the destination network address. - RemoteAddr() net.Addr - - // LocalAddr returns the local client network address. - LocalAddr() net.Addr - - // Read reads data comming from TUN, note that it reads from an - // underlying pipe that the writer writes in the lwip thread, - // write op blocks until previous written data is consumed, one - // should read out all data as soon as possible. - Read(data []byte) (int, error) - - // Write writes data to TUN. - Write(data []byte) (int, error) - - // Close closes the connection. - Close() error - - // CloseWrite closes the writing side by sending a FIN - // segment to local peer. That means we can write no further - // data to TUN. - CloseWrite() error - - // CloseRead closes the reading side. That means we can no longer - // read more from TUN. - CloseRead() error - - // Abort aborts the connection by sending a RST segment. - Abort() - - SetDeadline(t time.Time) error - SetReadDeadline(t time.Time) error - SetWriteDeadline(t time.Time) error -} - -// TCPConn abstracts a UDP connection comming from TUN. This connection -// should be handled by a registered UDP proxy handler. -type UDPConn interface { - // LocalAddr returns the local client network address. - LocalAddr() *net.UDPAddr - - // ReceiveTo will be called when data arrives from TUN, and the received - // data should be sent to addr. - ReceiveTo(data []byte, addr *net.UDPAddr) error - - // WriteFrom writes data to TUN, addr will be set as source address of - // UDP packets that output to TUN. - WriteFrom(data []byte, addr *net.UDPAddr) (int, error) - - // Close closes the connection. - Close() error -} diff --git a/core/core_test.go b/core/core_test.go deleted file mode 100755 index 9b5e1ad..0000000 --- a/core/core_test.go +++ /dev/null @@ -1,134 +0,0 @@ -package core - -import ( - "bytes" - "encoding/hex" - "net" - "sync" - "testing" -) - -const ( - ipv4Header = 20 // Length of the IPv4 header in bytes. - udpHeader = 8 // Length of the UDP header in bytes. - // A small NTP query packet (UDP) - ntpHex = "45b8004c72e94000401125a2646a4100d8ef2304007b007b0038a1a7230209e8000003620000072ed8ef230ce10ff888c730e992e10ffbdbc742a583e10ffbdbcaa4151ae10ffde6c3cf01e3" - // Two fragments of a large UDP packet. - frag1Hex = "450003fc0001200040117bab646a41005db8d8220afa00000774af62691c476d4d1f5bd3b2d5f17b926562b91de7ab5ee5bea9fe13ed6223891668ab17e4236a4ec1bed53fb9db397f2885e0fd418dbe2f29416b3e01dfa633bd72d1486e6aa39d568a4b9906834ba06d0c39f9696cbbe96c13638c4cef0fedab2f17d9aa3eb87b6fcf7a3e614cbf7cc7141fbf174d97ef220f17d7e669752bad3965785ec1355b19a3adea31a6c148a0b77ade200962dc4f02ad302e1f927c537627dc1f56f613e1a9d69847a8adc5b965059e973312c013f3916f6c54ddedb96605590f9d81e39e3649d007a44e1b57d9086487c073b511da5b868a44ad043e013feb23903eade049bcac0c0486c6e832aabce435a054159242a27784260bdbe8318f677dc58cbcc90f5ec7a065504b8ddd66c5a53480e634deed9b075a9d23dbabd37c97a825e2c6d17b179bbe83a35b09c852db9aa8d04ee23f285d83c68ae808c1a16cb2ed7c93e1d9724c1e0f4e413dfd50814f12d648201bc3352dd87640609937db0eef31c335b182e6969b32a50cd7af1116013caeeccc9417d0918bbfb1320cdb6e215b6a0c70654bb196e99636b70c503d9d1837f1a33f4a43913390f2585b361c33912cf16ccbb0a5cfbba90be9c3a360cf11193b9738b1a1459860e0bb99418df9368174a9184aac6f9ecb1299876ce62ab5028f48cf6c93b58b4fb1ced3199d36ae9dfa4b4eb9109ca62f8b186c912939018a8257b79a93cec689223b04a62de256019d56dbe54ba989b1f22aa00ea81e50b0895b152d7841416e9f5ed209d99cb38534820c82b4298a8d93afdc134aa41a2e3cd62d43419873ac8d17487de28b15e186eefe538c2019023086923b3f9aec506589fb5504f483dd820993f6950262231cb0f914415d37a929a77c435ba3ecdab90a817d683abd4dc8028c3294770d4ee28ea71eb09fc027b9dc9afedc00fbe414eef5756d409909786c82186fce59f4305ad3ca47d72d59d2bff2224f5a2115f01bee7b71552160fefd14587f150a67ffc08e92c73f40d8ad7b6b900324ae56ea84eccdbb2872f644cea1b2e011e862f2dba10dbac8452f53a2c6c9ac9d5b33ab03fa16a1f146197d1c649ee2c65636f4973b916190107b1977fb55f4157ff57e62251d3a3e0fcc3357665c13287009a3f11fc0cfe4495a4b9bb981b0893fd06c938c5d99e3b7e68d6ad16326ea54314d5c6a428cf105bf95aea4e8374bd7ff81ecc5b6b9f050dc6482aa123c470d7c068a2f171949cb5dee61ddf3c40ec97099c527926dddb84b0ffa3f69564bb3b9632da0fc6914a80e2044793ac302e3763d762f42abc07b0ed52968f09e96ce3e5fa83822a5d35548973fdda478610fa39355db82bb4c743479743c32a93521082a131cd21439bca3735c8b01d295c67b8dfe8a0071487d8472" - frag2Hex = "450003a00001007d40119b8a646a41005db8d822c726296a575ed8996bdad7392375d166d9894a6f0c0c08e4ae1ae9e55ae13a9f206b15cf74a43bff8f579f85344b972e7298f8c56d6a23081c19a369488a1b680af5f2e96e7d650261ac937ac709b74f45d15aa053b734cea3f5cbf400379a0e30e49bf696640a61a86076d867834cb79e7bcb798d129a28a8d81f47448ddc38b6040bd45607013d839c9198daabf8ae2f2994908e8b5d04f3194fe2def74e95e52aaf313119b9cef0bde9232fb7a95003e5fdcb9d8b759cf52d570c75f885333b600348b93fe8d0ccaa113465e37f20ce72b432ecc9c8a25809c2b2ed201a88d39b7f47023651ed6841e50b8fb298ef703888d603cd02438ac2ca563ae1ee273da555c3929a6221467f122a60bdb6484bd99d22fd4f4f3bfc41fd39e49c090acf33f46544c0705dbeb03b7249d90a398eacfbf239bcbb279e2596b06d25cfb9c6e247c34a57d55a272797f27df4fd2fc0fb23623f7c4890e05133ab2fa4f02cdd44eecabb3a49d7abae7dcb95f1429c82a685c4f69901cf22e355e31916bd20d038efc66dc37387d63a4330c516d03b6a2dd23bb9228d94c225723487792ae62888282a41e8c1c834d68ae58b4db92243671fd171157439282cfbab316439224dfb522f304a788f91c52715dc6588f0e1055455f159a28865d97292a7af670ec78afb229fcfa7cb97590d51d7fc8eb40edef005b19c8fb235f41b3bb5f6f7923b7534bf8ca8437ef93f40fabeb49b9eb9c5e8de9ad27ad8de282cea26adf3ddbd5b3ea4537535e2ddb864b125e73d330bf25d923e3df41be562b8de3bb3ce969defb159bc77cacb2337b07ac5204d8f1a39520089932ca6649a742f63c7e5e2ab25dc4bbed75faf68796dd5d521aee6452fbecc6af63623a1c55ad02de7c727c265ef8a4cdd109d41a7be9a5597dc69c3803e77340f2dff5608817b9c6d7c340c351e451401599a6ede93a0a897bd9bfe2dba1bfc7b61683ee9ff266a8a49fbec63ea60e4a58473c3705404cd3b3ff96415fcc92672a045555f48418a7125f0f4bda7b2df2d367af6d0e9d27a1f3895148c002b1503c6b83efa2a1e93def67fa07937d355b04a193465094e16128f33017e892d0bd154b9b87985eb6571d074d6011863b5af1395972d9415b21bd83d971cf5f3f67cc73dc0ab057aad3c83af4f6b10d5a6d8102ee3fe9f25929a14306871bf579e56dfd69cf45dd1472bbfcb1f0ab7fbb3972e27e2aba98273383b50700872d73f5c2ecf6ce3ea384ec08c4818fcfe0ed86513d617025f52" -) - -var ntp, ntpPayload, frag1, frag2, fragPayload []byte - -func decode(s string) []byte { - b, err := hex.DecodeString(s) - if err != nil { - panic(err) - } - return b -} - -// This is a trivial UDP handler that sends each received packet to a channel for inspection. -type fakeUDPHandler struct { - UDPConnHandler - packets chan []byte -} - -func (h *fakeUDPHandler) Connect(conn UDPConn, target *net.UDPAddr) error { - return nil -} - -func (h *fakeUDPHandler) ReceiveTo(conn UDPConn, data []byte, addr *net.UDPAddr) error { - h.packets <- data - return nil -} - -func setupUDP(t *testing.T) (LWIPStack, *fakeUDPHandler) { - // Reinitialize source data before each test to avoid interference. - ntp = decode(ntpHex) - ntpPayload = ntp[ipv4Header+udpHeader:] - frag1 = decode(frag1Hex) - frag2 = decode(frag2Hex) - fragPayload = append([]byte(nil), frag1[ipv4Header+udpHeader:]...) - fragPayload = append(fragPayload, frag2[ipv4Header:]...) - - // Reset the set of known UDP connections to empty before each test. Otherwise, the - // tests will interfere with each other. - udpConns = sync.Map{} - - s := NewLWIPStack() - // This channel is buffered because the first Write->ReceiveTo can either be synchronous or - // asynchronous, depending on the results of a race during "connection". - h := &fakeUDPHandler{packets: make(chan []byte, 1)} - RegisterUDPConnHandler(h) - return s, h -} - -func write(s LWIPStack, b []byte, t *testing.T) { - if _, err := s.Write(b); err != nil { - t.Fatal(err) - } -} - -func checkedCopy(dst, src []byte, t *testing.T) { - if copy(dst, src) != len(src) { - t.Fatal("Copy failed due to test misconfiguration") - } -} - -func assertEqual(actual, expected []byte, t *testing.T) { - if !bytes.Equal(actual, expected) { - t.Error("Payloads are not equal") - } -} - -// Basic test for sending a single UDP packet. -func TestUDP(t *testing.T) { - s, h := setupUDP(t) - write(s, ntp, t) - assertEqual(<-h.packets, ntpPayload, t) -} - -// Send a fragmented UDP packet. -func TestUDPFragmentation(t *testing.T) { - s, h := setupUDP(t) - write(s, frag1, t) - write(s, frag2, t) - assertEqual(<-h.packets, fragPayload, t) -} - -// Write UDP fragments out of order. -func TestUDPFragmentReordering(t *testing.T) { - s, h := setupUDP(t) - write(s, frag2, t) - write(s, frag1, t) - assertEqual(<-h.packets, fragPayload, t) -} - -// Send a fragmented UDP packet where fragments reuse the same buffer. -func TestUDPFragmentationMemory(t *testing.T) { - s, h := setupUDP(t) - buf := make([]byte, len(frag1)) - - checkedCopy(buf, frag1, t) - write(s, buf[:len(frag1)], t) - - checkedCopy(buf, frag2, t) - write(s, buf[:len(frag2)], t) - - assertEqual(<-h.packets, fragPayload, t) -} - -// Regression test for a segmentation fault. -func TestUDPFragmentationMemoryAndReordering(t *testing.T) { - s, h := setupUDP(t) - buf := make([]byte, len(frag1)) - - checkedCopy(buf, frag2, t) - write(s, buf[:len(frag2)], t) - - checkedCopy(buf, frag1, t) - write(s, buf[:len(frag1)], t) - - assertEqual(<-h.packets, fragPayload, t) -} diff --git a/core/errors.go b/core/errors.go deleted file mode 100755 index 0e0e7a4..0000000 --- a/core/errors.go +++ /dev/null @@ -1,60 +0,0 @@ -package core - -// Error codes defined in lwIP. -// /** Definitions for error constants. */ -// typedef enum { -// /** No error, everything 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, -// /** Address in use. */ -// ERR_USE = -8, -// /** Already connecting. */ -// ERR_ALREADY = -9, -// /** Conn already established.*/ -// ERR_ISCONN = -10, -// /** Not connected. */ -// ERR_CONN = -11, -// /** Low-level netif error */ -// ERR_IF = -12, -// -// /** Connection aborted. */ -// ERR_ABRT = -13, -// /** Connection reset. */ -// ERR_RST = -14, -// /** Connection closed. */ -// ERR_CLSD = -15, -// /** Illegal argument. */ -// ERR_ARG = -16 -// } err_enum_t; - -const ( - LWIP_ERR_OK int = iota - LWIP_ERR_ABRT - LWIP_ERR_CONN - LWIP_ERR_CLSD -) - -type lwipError struct { - Code int -} - -func NewLWIPError(code int) error { - return &lwipError{Code: code} -} - -func (e *lwipError) Error() string { - return "error code " + string(e.Code) -} diff --git a/core/handler.go b/core/handler.go deleted file mode 100755 index e23d10a..0000000 --- a/core/handler.go +++ /dev/null @@ -1,31 +0,0 @@ -package core - -import ( - "net" -) - -// TCPConnHandler handles TCP connections comming from TUN. -type TCPConnHandler interface { - // Handle handles the conn for target. - Handle(conn net.Conn, target *net.TCPAddr) error -} - -// UDPConnHandler handles UDP connections comming from TUN. -type UDPConnHandler interface { - // Connect connects the proxy server. Note that target can be nil. - Connect(conn UDPConn, target *net.UDPAddr) error - - // ReceiveTo will be called when data arrives from TUN. - ReceiveTo(conn UDPConn, data []byte, addr *net.UDPAddr) error -} - -var tcpConnHandler TCPConnHandler -var udpConnHandler UDPConnHandler - -func RegisterTCPConnHandler(h TCPConnHandler) { - tcpConnHandler = h -} - -func RegisterUDPConnHandler(h UDPConnHandler) { - udpConnHandler = h -} diff --git a/core/input.go b/core/input.go deleted file mode 100755 index 66a7f68..0000000 --- a/core/input.go +++ /dev/null @@ -1,127 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/pbuf.h" -#include "lwip/tcp.h" - -err_t -input(struct pbuf *p) -{ - return (*netif_list).input(p, netif_list); -} -*/ -import "C" -import ( - "encoding/binary" - "errors" - "unsafe" -) - -type ipver byte - -const ( - ipv4 = 4 - ipv6 = 6 -) - -type proto byte - -const ( - proto_icmp = 1 - proto_tcp = 6 - proto_udp = 17 -) - -func peekIPVer(p []byte) (ipver, error) { - if len(p) < 1 { - return 0, errors.New("short IP packet") - } - return ipver((p[0] & 0xf0) >> 4), nil -} - -func moreFrags(ipv ipver, p []byte) bool { - switch ipv { - case ipv4: - if (p[6] & 0x20) > 0 /* has MF (More Fragments) bit set */ { - return true - } - case ipv6: - // FIXME Just too lazy to implement this for IPv6, for now - // returning true simply indicate do the copy anyway. - return true - } - return false -} - -func fragOffset(ipv ipver, p []byte) uint16 { - switch ipv { - case ipv4: - return binary.BigEndian.Uint16(p[6:8]) & 0x1fff - case ipv6: - // FIXME Just too lazy to implement this for IPv6, for now - // returning a value greater than 0 simply indicate do the - // copy anyway. - return 1 - } - return 0 -} - -func peekNextProto(ipv ipver, p []byte) (proto, error) { - switch ipv { - case ipv4: - if len(p) < 9 { - return 0, errors.New("short IPv4 packet") - } - return proto(p[9]), nil - case ipv6: - if len(p) < 6 { - return 0, errors.New("short IPv6 packet") - } - return proto(p[6]), nil - default: - return 0, errors.New("unknown IP version") - } -} - -func input(pkt []byte) (int, error) { - if len(pkt) == 0 { - return 0, nil - } - - ipv, err := peekIPVer(pkt) - if err != nil { - return 0, err - } - - nextProto, err := peekNextProto(ipv, pkt) - if err != nil { - return 0, err - } - - lwipMutex.Lock() - defer lwipMutex.Unlock() - - var buf *C.struct_pbuf - - if nextProto == proto_udp && !(moreFrags(ipv, pkt) || fragOffset(ipv, pkt) > 0) { - // Copying data is not necessary for unfragmented UDP packets, and we would like to - // have all data in one pbuf. - buf = C.pbuf_alloc_reference(unsafe.Pointer(&pkt[0]), C.u16_t(len(pkt)), C.PBUF_REF) - } else { - // TODO Copy the data only when lwip need to keep it, e.g. in - // case we are returning ERR_CONN in tcpRecvFn. - // - // Allocating from PBUF_POOL results in a pbuf chain that may - // contain multiple pbufs. - buf = C.pbuf_alloc(C.PBUF_RAW, C.u16_t(len(pkt)), C.PBUF_POOL) - C.pbuf_take(buf, unsafe.Pointer(&pkt[0]), C.u16_t(len(pkt))) - } - - ierr := C.input(buf) - if ierr != C.ERR_OK { - C.pbuf_free(buf) - return 0, errors.New("packet not handled") - } - return len(pkt), nil -} diff --git a/core/lwip.go b/core/lwip.go deleted file mode 100755 index 9ba76e4..0000000 --- a/core/lwip.go +++ /dev/null @@ -1,170 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/tcp.h" -#include "lwip/udp.h" -#include "lwip/timeouts.h" -*/ -import "C" -import ( - "context" - "errors" - "sync" - "time" - "unsafe" -) - -const CHECK_TIMEOUTS_INTERVAL = 250 // in millisecond -const TCP_POLL_INTERVAL = 8 // poll every 4 seconds - -type LWIPStack interface { - Write([]byte) (int, error) - Close() error - RestartTimeouts() -} - -// lwIP runs in a single thread, locking is needed in Go runtime. -var lwipMutex = &sync.Mutex{} - -type lwipStack struct { - tpcb *C.struct_tcp_pcb - upcb *C.struct_udp_pcb - - ctx context.Context - cancel context.CancelFunc -} - -// NewLWIPStack listens for any incoming connections/packets and registers -// corresponding accept/recv callback functions. -func NewLWIPStack() LWIPStack { - tcpPCB := C.tcp_new() - if tcpPCB == nil { - panic("tcp_new return nil") - } - - err := C.tcp_bind(tcpPCB, C.IP_ADDR_ANY, 0) - switch err { - case C.ERR_OK: - break - case C.ERR_VAL: - panic("invalid PCB state") - case C.ERR_USE: - panic("port in use") - default: - C.memp_free(C.MEMP_TCP_PCB, unsafe.Pointer(tcpPCB)) - panic("unknown tcp_bind return value") - } - - tcpPCB = C.tcp_listen_with_backlog(tcpPCB, C.TCP_DEFAULT_LISTEN_BACKLOG) - if tcpPCB == nil { - panic("can not allocate tcp pcb") - } - - setTCPAcceptCallback(tcpPCB) - - udpPCB := C.udp_new() - if udpPCB == nil { - panic("could not allocate udp pcb") - } - - err = C.udp_bind(udpPCB, C.IP_ADDR_ANY, 0) - if err != C.ERR_OK { - panic("address already in use") - } - - setUDPRecvCallback(udpPCB, nil) - - ctx, cancel := context.WithCancel(context.Background()) - - go func() { - for { - select { - case <-time.After(CHECK_TIMEOUTS_INTERVAL * time.Millisecond): - lwipMutex.Lock() - C.sys_check_timeouts() - lwipMutex.Unlock() - case <-ctx.Done(): - return - } - } - }() - - return &lwipStack{ - tpcb: tcpPCB, - upcb: udpPCB, - ctx: ctx, - cancel: cancel, - } -} - -// Write writes IP packets to the stack. -func (s *lwipStack) Write(data []byte) (int, error) { - select { - case <-s.ctx.Done(): - return 0, errors.New("stack closed") - default: - return input(data) - } -} - -// RestartTimeouts rebases the timeout times to the current time. -// -// 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. -func (s *lwipStack) RestartTimeouts() { - lwipMutex.Lock() - C.sys_restart_timeouts() - lwipMutex.Unlock() -} - -// Close closes the stack. -// -// Timer events will be canceled and existing connections will be closed. -// Note this function will not free objects allocated in lwIP initialization -// stage, e.g. the loop interface. -func (s *lwipStack) Close() error { - // Stop firing timer events. - s.cancel() - - // Abort and close all TCP and UDP connections. - tcpConns.Range(func(_, c interface{}) bool { - c.(*tcpConn).Abort() - return true - }) - udpConns.Range(func(_, c interface{}) bool { - // This only closes UDP connections in the core, - // UDP connections in the handler will wait till - // timeout, they are not closed immediately for - // now. - c.(*udpConn).Close() - return true - }) - - // Remove callbacks and close listening pcbs. - lwipMutex.Lock() - C.tcp_accept(s.tpcb, nil) - C.udp_recv(s.upcb, nil, nil) - C.tcp_close(s.tpcb) // FIXME handle error - C.udp_remove(s.upcb) - lwipMutex.Unlock() - - return nil -} - -func init() { - // Initialize lwIP. - // - // There is a little trick here, a loop interface (127.0.0.1) - // is created in the initialization stage due to the option - // `#define LWIP_HAVE_LOOPIF 1` in `lwipopts.h`, so we need - // not create our own interface. - // - // Now the loop interface is just the first element in - // `C.netif_list`, i.e. `*C.netif_list`. - lwipInit() - - // Set MTU. - C.netif_list.mtu = 1500 -} diff --git a/core/lwip_other.go b/core/lwip_other.go deleted file mode 100755 index d57be78..0000000 --- a/core/lwip_other.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build linux darwin - -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/init.h" -*/ -import "C" - -func lwipInit() { - C.lwip_init() // Initialze modules. -} diff --git a/core/lwip_windows.go b/core/lwip_windows.go deleted file mode 100755 index 3844e89..0000000 --- a/core/lwip_windows.go +++ /dev/null @@ -1,15 +0,0 @@ -// +build windows - -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/sys.h" -#include "lwip/init.h" -*/ -import "C" - -func lwipInit() { - C.sys_init() // Initialze sys_arch layer, must be called before anything else. - C.lwip_init() // Initialze modules. -} diff --git a/core/output.go b/core/output.go deleted file mode 100755 index 3c878e8..0000000 --- a/core/output.go +++ /dev/null @@ -1,46 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/tcp.h" - -extern err_t output(struct pbuf *p); - -err_t -output_ip4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) -{ - return output(p); -} - -err_t -output_ip6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) -{ - return output(p); -} - -void -set_output() -{ - if (netif_list != NULL) { - (*netif_list).output = output_ip4; - (*netif_list).output_ip6 = output_ip6; - } -} -*/ -import "C" -import ( - "errors" -) - -var OutputFn func([]byte) (int, error) - -func RegisterOutputFn(fn func([]byte) (int, error)) { - OutputFn = fn - C.set_output() -} - -func init() { - OutputFn = func(data []byte) (int, error) { - return 0, errors.New("output function not set") - } -} diff --git a/core/output_export.go b/core/output_export.go deleted file mode 100755 index 79ae18a..0000000 --- a/core/output_export.go +++ /dev/null @@ -1,28 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/tcp.h" -*/ -import "C" -import ( - "unsafe" -) - -//export output -func output(p *C.struct_pbuf) C.err_t { - // In most case, all data are in the same pbuf struct, data copying can be avoid by - // backing Go slice with C array. Buf if there are multiple pbuf structs holding the - // data, we must copy data for sending them in one pass. - totlen := int(p.tot_len) - if p.tot_len == p.len { - buf := (*[1 << 30]byte)(unsafe.Pointer(p.payload))[:totlen:totlen] - OutputFn(buf[:totlen]) - } else { - buf := NewBytes(totlen) - C.pbuf_copy_partial(p, unsafe.Pointer(&buf[0]), p.tot_len, 0) // data copy here! - OutputFn(buf[:totlen]) - FreeBytes(buf) - } - return C.ERR_OK -} diff --git a/core/tcp_callback.go b/core/tcp_callback.go deleted file mode 100755 index ba385b1..0000000 --- a/core/tcp_callback.go +++ /dev/null @@ -1,62 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/tcp.h" - -extern err_t tcpAcceptFn(void *arg, struct tcp_pcb *newpcb, err_t err); - -void -set_tcp_accept_callback(struct tcp_pcb *pcb) { - tcp_accept(pcb, tcpAcceptFn); -} - -extern err_t tcpRecvFn(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); - -void -set_tcp_recv_callback(struct tcp_pcb *pcb) { - tcp_recv(pcb, tcpRecvFn); -} - -extern err_t tcpSentFn(void *arg, struct tcp_pcb *tpcb, u16_t len); - -void -set_tcp_sent_callback(struct tcp_pcb *pcb) { - tcp_sent(pcb, tcpSentFn); -} - -extern void tcpErrFn(void *arg, err_t err); - -void -set_tcp_err_callback(struct tcp_pcb *pcb) { - tcp_err(pcb, tcpErrFn); -} - -extern err_t tcpPollFn(void *arg, struct tcp_pcb *tpcb); - -void -set_tcp_poll_callback(struct tcp_pcb *pcb, u8_t interval) { - tcp_poll(pcb, tcpPollFn, interval); -} -*/ -import "C" - -func setTCPAcceptCallback(pcb *C.struct_tcp_pcb) { - C.set_tcp_accept_callback(pcb) -} - -func setTCPRecvCallback(pcb *C.struct_tcp_pcb) { - C.set_tcp_recv_callback(pcb) -} - -func setTCPSentCallback(pcb *C.struct_tcp_pcb) { - C.set_tcp_sent_callback(pcb) -} - -func setTCPErrCallback(pcb *C.struct_tcp_pcb) { - C.set_tcp_err_callback(pcb) -} - -func setTCPPollCallback(pcb *C.struct_tcp_pcb, interval C.u8_t) { - C.set_tcp_poll_callback(pcb, interval) -} diff --git a/core/tcp_callback_export.go b/core/tcp_callback_export.go deleted file mode 100755 index e936fe8..0000000 --- a/core/tcp_callback_export.go +++ /dev/null @@ -1,165 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/tcp.h" -*/ -import "C" -import ( - "errors" - "fmt" - "unsafe" -) - -// These exported callback functions must be placed in a seperated file. -// -// See also: -// https://github.com/golang/go/issues/20639 -// https://golang.org/cmd/cgo/#hdr-C_references_to_Go - -//export tcpAcceptFn -func tcpAcceptFn(arg unsafe.Pointer, newpcb *C.struct_tcp_pcb, err C.err_t) C.err_t { - if err != C.ERR_OK { - return err - } - - if tcpConnHandler == nil { - panic("must register a TCP connection handler") - } - - if _, nerr := newTCPConn(newpcb, tcpConnHandler); nerr != nil { - switch nerr.(*lwipError).Code { - case LWIP_ERR_ABRT: - return C.ERR_ABRT - case LWIP_ERR_OK: - return C.ERR_OK - default: - return C.ERR_CONN - } - } - - return C.ERR_OK -} - -//export tcpRecvFn -func tcpRecvFn(arg unsafe.Pointer, tpcb *C.struct_tcp_pcb, p *C.struct_pbuf, err C.err_t) C.err_t { - if err != C.ERR_OK && err != C.ERR_ABRT { - return err - } - - // Only free the pbuf when returning ERR_OK or ERR_ABRT, - // otherwise must not free the pbuf. - shouldFreePbuf := true - defer func() { - if p != nil && shouldFreePbuf { - C.pbuf_free(p) - } - }() - - conn, ok := tcpConns.Load(getConnKeyVal(arg)) - if !ok { - // The connection does not exists. - C.tcp_abort(tpcb) - return C.ERR_ABRT - } - - if p == nil { - // Peer closed, EOF. - err := conn.(TCPConn).LocalClosed() - switch err.(*lwipError).Code { - case LWIP_ERR_ABRT: - return C.ERR_ABRT - case LWIP_ERR_OK: - return C.ERR_OK - default: - panic("unexpected error") - } - } - - var buf []byte - var totlen = int(p.tot_len) - if p.tot_len == p.len { - buf = (*[1 << 30]byte)(unsafe.Pointer(p.payload))[:totlen:totlen] - } else { - buf = NewBytes(totlen) - defer FreeBytes(buf) - C.pbuf_copy_partial(p, unsafe.Pointer(&buf[0]), p.tot_len, 0) - } - - rerr := conn.(TCPConn).Receive(buf[:totlen]) - if rerr != nil { - switch rerr.(*lwipError).Code { - case LWIP_ERR_ABRT: - return C.ERR_ABRT - case LWIP_ERR_OK: - return C.ERR_OK - case LWIP_ERR_CONN: - shouldFreePbuf = false - // Tell lwip we can't receive data at the moment, - // lwip will store it and try again later. - return C.ERR_CONN - case LWIP_ERR_CLSD: - // lwip won't handle ERR_CLSD error for us, manually - // shuts down the rx side. - C.tcp_recved(tpcb, p.tot_len) - C.tcp_shutdown(tpcb, 1, 0) - return C.ERR_OK - default: - panic("unexpected error") - } - } - - return C.ERR_OK -} - -//export tcpSentFn -func tcpSentFn(arg unsafe.Pointer, tpcb *C.struct_tcp_pcb, len C.u16_t) C.err_t { - if conn, ok := tcpConns.Load(getConnKeyVal(arg)); ok { - err := conn.(TCPConn).Sent(uint16(len)) - switch err.(*lwipError).Code { - case LWIP_ERR_ABRT: - return C.ERR_ABRT - case LWIP_ERR_OK: - return C.ERR_OK - default: - panic("unexpected error") - } - } else { - C.tcp_abort(tpcb) - return C.ERR_ABRT - } -} - -//export tcpErrFn -func tcpErrFn(arg unsafe.Pointer, err C.err_t) { - if conn, ok := tcpConns.Load(getConnKeyVal(arg)); ok { - switch err { - case C.ERR_ABRT: - // Aborted through tcp_abort or by a TCP timer - conn.(TCPConn).Err(errors.New("connection aborted")) - case C.ERR_RST: - // The connection was reset by the remote host - conn.(TCPConn).Err(errors.New("connection reseted")) - default: - conn.(TCPConn).Err(errors.New(fmt.Sprintf("lwip error code %v", int(err)))) - } - } -} - -//export tcpPollFn -func tcpPollFn(arg unsafe.Pointer, tpcb *C.struct_tcp_pcb) C.err_t { - if conn, ok := tcpConns.Load(getConnKeyVal(arg)); ok { - err := conn.(TCPConn).Poll() - switch err.(*lwipError).Code { - case LWIP_ERR_ABRT: - return C.ERR_ABRT - case LWIP_ERR_OK: - return C.ERR_OK - default: - panic("unexpected error") - } - } else { - C.tcp_abort(tpcb) - return C.ERR_ABRT - } -} diff --git a/core/tcp_conn.go b/core/tcp_conn.go deleted file mode 100755 index 9052c1e..0000000 --- a/core/tcp_conn.go +++ /dev/null @@ -1,470 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/tcp.h" -*/ -import "C" -import ( - "errors" - "fmt" - "io" - "math/rand" - "net" - "sync" - "time" - "unsafe" -) - -type tcpConnState uint - -const ( - // tcpNewConn is the initial state. - tcpNewConn tcpConnState = iota - - // tcpConnecting indicates the handler is still connecting remote host. - tcpConnecting - - // tcpConnected indicates the connection has been established, handler - // may write data to TUN, and read data from TUN. - tcpConnected - - // tcpWriteClosed indicates the handler has closed the writing side - // of the connection, no more data will send to TUN, but handler can still - // read data from TUN. - tcpWriteClosed - - // tcpReceiveClosed indicates lwIP has received a FIN segment from - // local peer, the reading side is closed, no more data can be read - // from TUN, but handler can still write data to TUN. - tcpReceiveClosed - - // tcpClosing indicates both reading side and writing side are closed, - // resources deallocation will be triggered at any time in lwIP callbacks. - tcpClosing - - // tcpAborting indicates the connection is aborting, resources deallocation - // will be triggered at any time in lwIP callbacks. - tcpAborting - - // tcpClosed indicates the connection has been closed, resources were freed. - tcpClosed - - // tcpErrord indicates an fatal error occured on the connection, resources - // were freed. - tcpErrored -) - -type tcpConn struct { - sync.Mutex - - pcb *C.struct_tcp_pcb - handler TCPConnHandler - remoteAddr *net.TCPAddr - localAddr *net.TCPAddr - connKeyArg unsafe.Pointer - connKey uint32 - canWrite *sync.Cond // Condition variable to implement TCP backpressure. - state tcpConnState - sndPipeReader *io.PipeReader - sndPipeWriter *io.PipeWriter - closeOnce sync.Once - closeErr error -} - -func newTCPConn(pcb *C.struct_tcp_pcb, handler TCPConnHandler) (TCPConn, error) { - connKeyArg := newConnKeyArg() - connKey := rand.Uint32() - setConnKeyVal(unsafe.Pointer(connKeyArg), connKey) - - // Pass the key as arg for subsequent tcp callbacks. - C.tcp_arg(pcb, unsafe.Pointer(connKeyArg)) - - // Register callbacks. - setTCPRecvCallback(pcb) - setTCPSentCallback(pcb) - setTCPErrCallback(pcb) - setTCPPollCallback(pcb, C.u8_t(TCP_POLL_INTERVAL)) - - pipeReader, pipeWriter := io.Pipe() - conn := &tcpConn{ - pcb: pcb, - handler: handler, - localAddr: ParseTCPAddr(ipAddrNTOA(pcb.remote_ip), uint16(pcb.remote_port)), - remoteAddr: ParseTCPAddr(ipAddrNTOA(pcb.local_ip), uint16(pcb.local_port)), - connKeyArg: connKeyArg, - connKey: connKey, - canWrite: sync.NewCond(&sync.Mutex{}), - state: tcpNewConn, - sndPipeReader: pipeReader, - sndPipeWriter: pipeWriter, - } - - // Associate conn with key and save to the global map. - tcpConns.Store(connKey, conn) - - // Connecting remote host could take some time, do it in another goroutine - // to prevent blocking the lwip thread. - conn.Lock() - conn.state = tcpConnecting - conn.Unlock() - go func() { - err := handler.Handle(TCPConn(conn), conn.remoteAddr) - if err != nil { - conn.Abort() - } else { - conn.Lock() - conn.state = tcpConnected - conn.Unlock() - - lwipMutex.Lock() - if pcb.refused_data != nil { - C.tcp_process_refused_data(pcb) - } - lwipMutex.Unlock() - } - }() - - return conn, NewLWIPError(LWIP_ERR_OK) -} - -func (conn *tcpConn) RemoteAddr() net.Addr { - return conn.remoteAddr -} - -func (conn *tcpConn) LocalAddr() net.Addr { - return conn.localAddr -} - -func (conn *tcpConn) SetDeadline(t time.Time) error { - return nil -} -func (conn *tcpConn) SetReadDeadline(t time.Time) error { - return nil -} -func (conn *tcpConn) SetWriteDeadline(t time.Time) error { - return nil -} - -func (conn *tcpConn) receiveCheck() error { - conn.Lock() - defer conn.Unlock() - - switch conn.state { - case tcpConnected: - fallthrough - case tcpWriteClosed: - return nil - case tcpNewConn: - fallthrough - case tcpConnecting: - fallthrough - case tcpAborting: - fallthrough - case tcpClosed: - return NewLWIPError(LWIP_ERR_CONN) - case tcpReceiveClosed: - fallthrough - case tcpClosing: - return NewLWIPError(LWIP_ERR_CLSD) - case tcpErrored: - conn.abortInternal() - return NewLWIPError(LWIP_ERR_ABRT) - default: - panic("unexpected error") - } - return nil -} - -func (conn *tcpConn) Receive(data []byte) error { - if err := conn.receiveCheck(); err != nil { - return err - } - n, err := conn.sndPipeWriter.Write(data) - if err != nil { - return NewLWIPError(LWIP_ERR_CLSD) - } - C.tcp_recved(conn.pcb, C.u16_t(n)) - return NewLWIPError(LWIP_ERR_OK) -} - -func (conn *tcpConn) Read(data []byte) (int, error) { - conn.Lock() - if conn.state == tcpReceiveClosed { - conn.Unlock() - return 0, io.EOF - } - if conn.state >= tcpClosing { - conn.Unlock() - return 0, io.ErrClosedPipe - } - conn.Unlock() - - // Handler should get EOF. - n, err := conn.sndPipeReader.Read(data) - if err == io.ErrClosedPipe { - err = io.EOF - } - return n, err -} - -// writeInternal enqueues data to snd_buf, and treats ERR_MEM returned by tcp_write not an error, -// but instead tells the caller that data is not successfully enqueued, and should try -// again another time. By calling this function, the lwIP thread is assumed to be already -// locked by the caller. -func (conn *tcpConn) writeInternal(data []byte) (int, error) { - err := C.tcp_write(conn.pcb, unsafe.Pointer(&data[0]), C.u16_t(len(data)), C.TCP_WRITE_FLAG_COPY) - if err == C.ERR_OK { - C.tcp_output(conn.pcb) - return len(data), nil - } else if err == C.ERR_MEM { - return 0, nil - } - return 0, fmt.Errorf("tcp_write failed (%v)", int(err)) -} - -func (conn *tcpConn) writeCheck() error { - conn.Lock() - defer conn.Unlock() - - switch conn.state { - case tcpConnecting: - fallthrough - case tcpConnected: - fallthrough - case tcpReceiveClosed: - return nil - case tcpWriteClosed: - fallthrough - case tcpClosing: - fallthrough - case tcpClosed: - fallthrough - case tcpErrored: - fallthrough - case tcpAborting: - return io.ErrClosedPipe - default: - panic("unexpected error") - } - return nil -} - -func (conn *tcpConn) Write(data []byte) (int, error) { - totalWritten := 0 - - conn.canWrite.L.Lock() - defer conn.canWrite.L.Unlock() - - for len(data) > 0 { - if err := conn.writeCheck(); err != nil { - return totalWritten, err - } - - lwipMutex.Lock() - toWrite := len(data) - if toWrite > int(conn.pcb.snd_buf) { - // Write at most the size of the LWIP buffer. - toWrite = int(conn.pcb.snd_buf) - } - if toWrite > 0 { - written, err := conn.writeInternal(data[0:toWrite]) - totalWritten += written - if err != nil { - lwipMutex.Unlock() - return totalWritten, err - } - data = data[written:len(data)] - } - lwipMutex.Unlock() - if len(data) == 0 { - break // Don't block if all the data has been written. - } - conn.canWrite.Wait() - } - - return totalWritten, nil -} - -func (conn *tcpConn) CloseWrite() error { - conn.Lock() - if conn.state >= tcpClosing || conn.state == tcpWriteClosed { - conn.Unlock() - return nil - } - if conn.state == tcpReceiveClosed { - conn.state = tcpClosing - } else { - conn.state = tcpWriteClosed - } - conn.Unlock() - - lwipMutex.Lock() - // FIXME Handle tcp_shutdown error. - C.tcp_shutdown(conn.pcb, 0, 1) - lwipMutex.Unlock() - - return nil -} - -func (conn *tcpConn) CloseRead() error { - return conn.sndPipeReader.Close() -} - -func (conn *tcpConn) Sent(len uint16) error { - // Some packets are acknowledged by local client, check if any pending data to send. - return conn.checkState() -} - -func (conn *tcpConn) checkClosing() error { - conn.Lock() - defer conn.Unlock() - - if conn.state == tcpClosing { - conn.closeInternal() - return NewLWIPError(LWIP_ERR_OK) - } - return nil -} - -func (conn *tcpConn) checkAborting() error { - conn.Lock() - defer conn.Unlock() - - if conn.state == tcpAborting { - conn.abortInternal() - return NewLWIPError(LWIP_ERR_ABRT) - } - return nil -} - -func (conn *tcpConn) isClosed() bool { - conn.Lock() - defer conn.Unlock() - - return conn.state == tcpClosed -} - -func (conn *tcpConn) checkState() error { - if conn.isClosed() { - return nil - } - - err := conn.checkClosing() - if err != nil { - return err - } - - err = conn.checkAborting() - if err != nil { - return err - } - - // Signal the writer to try writting. - conn.canWrite.Broadcast() - - return NewLWIPError(LWIP_ERR_OK) -} - -func (conn *tcpConn) Close() error { - conn.closeOnce.Do(conn.close) - return conn.closeErr -} - -func (conn *tcpConn) close() { - err := conn.CloseRead() - if err != nil { - conn.closeErr = err - } - err = conn.CloseWrite() - if err != nil { - conn.closeErr = err - } -} - -func (conn *tcpConn) setLocalClosed() error { - conn.Lock() - defer conn.Unlock() - - if conn.state >= tcpClosing || conn.state == tcpReceiveClosed { - return nil - } - - // Causes the read half of the pipe returns. - conn.sndPipeWriter.Close() - - if conn.state == tcpWriteClosed { - conn.state = tcpClosing - } else { - conn.state = tcpReceiveClosed - } - conn.canWrite.Broadcast() - return nil -} - -// Never call this function outside of the lwIP thread. -func (conn *tcpConn) closeInternal() error { - C.tcp_arg(conn.pcb, nil) - C.tcp_recv(conn.pcb, nil) - C.tcp_sent(conn.pcb, nil) - C.tcp_err(conn.pcb, nil) - C.tcp_poll(conn.pcb, nil, 0) - - conn.release() - - // FIXME Handle error. - err := C.tcp_close(conn.pcb) - if err == C.ERR_OK { - return nil - } else { - return errors.New(fmt.Sprintf("close TCP connection failed, lwip error code %d", int(err))) - } -} - -// Never call this function outside of the lwIP thread since it calls -// tcp_abort() and in that case we must return ERR_ABRT to lwIP. -func (conn *tcpConn) abortInternal() { - conn.release() - C.tcp_abort(conn.pcb) -} - -func (conn *tcpConn) Abort() { - conn.Lock() - // If it's in tcpErrored state, the pcb was already freed. - if conn.state < tcpAborting { - conn.state = tcpAborting - } - conn.Unlock() - - lwipMutex.Lock() - conn.checkState() - lwipMutex.Unlock() -} - -func (conn *tcpConn) Err(err error) { - conn.Lock() - defer conn.Unlock() - - conn.release() - conn.state = tcpErrored - conn.canWrite.Broadcast() -} - -func (conn *tcpConn) LocalClosed() error { - conn.setLocalClosed() - return conn.checkState() -} - -func (conn *tcpConn) release() { - if _, found := tcpConns.Load(conn.connKey); found { - freeConnKeyArg(conn.connKeyArg) - tcpConns.Delete(conn.connKey) - } - conn.sndPipeWriter.Close() - conn.sndPipeReader.Close() - conn.state = tcpClosed -} - -func (conn *tcpConn) Poll() error { - return conn.checkState() -} diff --git a/core/tcp_conn_map.go b/core/tcp_conn_map.go deleted file mode 100755 index 881708e..0000000 --- a/core/tcp_conn_map.go +++ /dev/null @@ -1,65 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/tcp.h" -#include - -void* -new_conn_key_arg() -{ - return malloc(sizeof(uint32_t)); -} - -void -free_conn_key_arg(void *arg) -{ - free(arg); -} - -void -set_conn_key_val(void *arg, uint32_t val) -{ - *((uint32_t*)arg) = val; -} - -uint32_t -get_conn_key_val(void *arg) -{ - return *((uint32_t*)arg); -} -*/ -import "C" -import ( - "sync" - "unsafe" -) - -var tcpConns sync.Map - -// We need such a key-value mechanism because when passing a Go pointer -// to C, the Go pointer will only be valid during the call. -// If we pass a Go pointer to tcp_arg(), this pointer will not be usable -// in subsequent callbacks (e.g.: tcp_recv(), tcp_err()). -// -// Instead we need to pass a C pointer to tcp_arg(), we manually allocate -// the memory in C and return its pointer to Go code. After the connection -// end, the memory should be freed manually. -// -// See also: -// https://github.com/golang/go/issues/12416 -func newConnKeyArg() unsafe.Pointer { - return C.new_conn_key_arg() -} - -func freeConnKeyArg(p unsafe.Pointer) { - C.free_conn_key_arg(p) -} - -func setConnKeyVal(p unsafe.Pointer, val uint32) { - C.set_conn_key_val(p, C.uint32_t(val)) -} - -func getConnKeyVal(p unsafe.Pointer) uint32 { - return uint32(C.get_conn_key_val(p)) -} diff --git a/core/udp_callback.go b/core/udp_callback.go deleted file mode 100755 index 4d0151e..0000000 --- a/core/udp_callback.go +++ /dev/null @@ -1,21 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/udp.h" - -extern void udpRecvFn(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port, const ip_addr_t *dest_addr, u16_t dest_port); - -void -set_udp_recv_callback(struct udp_pcb *pcb, void *recv_arg) { - udp_recv(pcb, udpRecvFn, recv_arg); -} -*/ -import "C" -import ( - "unsafe" -) - -func setUDPRecvCallback(pcb *C.struct_udp_pcb, recvArg unsafe.Pointer) { - C.set_udp_recv_callback(pcb, recvArg) -} diff --git a/core/udp_callback_export.go b/core/udp_callback_export.go deleted file mode 100755 index db885a7..0000000 --- a/core/udp_callback_export.go +++ /dev/null @@ -1,62 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/udp.h" -*/ -import "C" -import ( - "unsafe" -) - -//export udpRecvFn -func udpRecvFn(arg unsafe.Pointer, pcb *C.struct_udp_pcb, p *C.struct_pbuf, addr *C.ip_addr_t, port C.u16_t, destAddr *C.ip_addr_t, destPort C.u16_t) { - defer func() { - if p != nil { - C.pbuf_free(p) - } - }() - - if pcb == nil { - return - } - - srcAddr := ParseUDPAddr(ipAddrNTOA(*addr), uint16(port)) - dstAddr := ParseUDPAddr(ipAddrNTOA(*destAddr), uint16(destPort)) - if srcAddr == nil || dstAddr == nil { - panic("invalid UDP address") - } - - connId := udpConnId{ - src: srcAddr.String(), - } - conn, found := udpConns.Load(connId) - if !found { - if udpConnHandler == nil { - panic("must register a UDP connection handler") - } - var err error - conn, err = newUDPConn(pcb, - udpConnHandler, - *addr, - port, - srcAddr, - dstAddr) - if err != nil { - return - } - udpConns.Store(connId, conn) - } - - var buf []byte - var totlen = int(p.tot_len) - if p.tot_len == p.len { - buf = (*[1 << 30]byte)(unsafe.Pointer(p.payload))[:totlen:totlen] - } else { - buf = NewBytes(totlen) - defer FreeBytes(buf) - C.pbuf_copy_partial(p, unsafe.Pointer(&buf[0]), p.tot_len, 0) - } - - conn.(UDPConn).ReceiveTo(buf[:totlen], dstAddr) -} diff --git a/core/udp_conn.go b/core/udp_conn.go deleted file mode 100755 index 195d506..0000000 --- a/core/udp_conn.go +++ /dev/null @@ -1,158 +0,0 @@ -package core - -/* -#cgo CFLAGS: -I./c/include -#include "lwip/udp.h" -*/ -import "C" -import ( - "errors" - "fmt" - "net" - "sync" - "unsafe" -) - -type udpConnState uint - -const ( - udpConnecting udpConnState = iota - udpConnected - udpClosed -) - -type udpPacket struct { - data []byte - addr *net.UDPAddr -} - -type udpConn struct { - sync.Mutex - - pcb *C.struct_udp_pcb - handler UDPConnHandler - localAddr *net.UDPAddr - localIP C.ip_addr_t - localPort C.u16_t - state udpConnState - pending chan *udpPacket -} - -func newUDPConn(pcb *C.struct_udp_pcb, handler UDPConnHandler, localIP C.ip_addr_t, localPort C.u16_t, localAddr, remoteAddr *net.UDPAddr) (UDPConn, error) { - conn := &udpConn{ - handler: handler, - pcb: pcb, - localAddr: localAddr, - localIP: localIP, - localPort: localPort, - state: udpConnecting, - pending: make(chan *udpPacket, 64), // To hold the early packets on the connection - } - - go func() { - err := handler.Connect(conn, remoteAddr) - if err != nil { - conn.Close() - } else { - conn.Lock() - conn.state = udpConnected - conn.Unlock() - // Once connected, send all pending data. - DrainPending: - for { - select { - case pkt := <-conn.pending: - err := conn.handler.ReceiveTo(conn, pkt.data, pkt.addr) - if err != nil { - break DrainPending - } - continue DrainPending - default: - conn.pending = nil - break DrainPending - } - } - } - }() - - return conn, nil -} - -func (conn *udpConn) LocalAddr() *net.UDPAddr { - return conn.localAddr -} - -func (conn *udpConn) checkState() error { - conn.Lock() - defer conn.Unlock() - - switch conn.state { - case udpClosed: - return errors.New("connection closed") - case udpConnected: - return nil - case udpConnecting: - return errors.New("not connected") - } - return nil -} - -// If the connection isn't ready yet, and there is room in the queue, make a copy -// and hold onto it until the connection is ready. -func (conn *udpConn) enqueueEarlyPacket(data []byte, addr *net.UDPAddr) bool { - conn.Lock() - defer conn.Unlock() - if conn.state == udpConnecting { - pkt := &udpPacket{data: append([]byte(nil), data...), addr: addr} - select { - // Data will be dropped if pending is full. - case conn.pending <- pkt: - return true - default: - } - } - return false -} - -func (conn *udpConn) ReceiveTo(data []byte, addr *net.UDPAddr) error { - if conn.enqueueEarlyPacket(data, addr) { - return nil - } - if err := conn.checkState(); err != nil { - return err - } - err := conn.handler.ReceiveTo(conn, data, addr) - if err != nil { - return errors.New(fmt.Sprintf("write proxy failed: %v", err)) - } - return nil -} - -func (conn *udpConn) WriteFrom(data []byte, addr *net.UDPAddr) (int, error) { - if len(data) == 0 { - return 0, nil - } - if err := conn.checkState(); err != nil { - return 0, err - } - // FIXME any memory leaks? - cremoteIP := C.struct_ip_addr{} - if err := ipAddrATON(addr.IP.String(), &cremoteIP); err != nil { - return 0, err - } - buf := C.pbuf_alloc_reference(unsafe.Pointer(&data[0]), C.u16_t(len(data)), C.PBUF_ROM) - defer C.pbuf_free(buf) - C.udp_sendto(conn.pcb, buf, &conn.localIP, conn.localPort, &cremoteIP, C.u16_t(addr.Port)) - return len(data), nil -} - -func (conn *udpConn) Close() error { - connId := udpConnId{ - src: conn.LocalAddr().String(), - } - conn.Lock() - conn.state = udpClosed - conn.Unlock() - udpConns.Delete(connId) - return nil -} diff --git a/core/udp_conn_map.go b/core/udp_conn_map.go deleted file mode 100755 index bd1b558..0000000 --- a/core/udp_conn_map.go +++ /dev/null @@ -1,11 +0,0 @@ -package core - -import ( - "sync" -) - -var udpConns sync.Map - -type udpConnId struct { - src string -} diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100644 index 728347f..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh - -TUN="${TUN:-tun0}" -ETH="${ETH:-eth0}" -TUN_ADDR="${TUN_ADDR:-198.18.0.1}" -TUN_MASK="${TUN_MASK:-255.254.0.0}" -LOGLEVEL="${LOGLEVEL:-warning}" - -MONITOR="${MONITOR:-1}" -MONITOR_ADDR="${MONITOR_ADDR:-0.0.0.0:80}" -FAKEDNS="${FAKEDNS:-1}" -BACKEND_DNS="${BACKEND_DNS:-8.8.8.8:53}" -HOSTS="${HOSTS:-localhost=127.0.0.1}" - -# create tun device -ip tuntap add mode tun dev "$TUN" -ip addr add "$TUN_ADDR"/"$TUN_MASK" dev "$TUN" -ip link set dev "$TUN" up - -# change default gateway -ip route del default > /dev/null -ip route add default via "$TUN_ADDR" dev "$TUN" - -# add to ip route -for addr in $(echo "$EXCLUDED" | tr ',' '\n') -do - ip route add "$addr" via "$ETH_ADDR" -done - -if [ -n "$EXTRACMD" ]; then - sh -c "$EXTRACMD" -fi - -if [ "$MONITOR" -ne 0 ]; then - ARGS="-monitor -monitorAddr $MONITOR_ADDR" -fi - -if [ "$FAKEDNS" -ne 0 ]; then - ARGS="$ARGS -fakeDNS -hosts $HOSTS -backendDNS $BACKEND_DNS" -fi - -eval exec /tun2socks -loglevel "$LOGLEVEL" \ - -tunName "$TUN" -proxyServer "$PROXY" "$ARGS" diff --git a/filter/filter.go b/filter/filter.go deleted file mode 100644 index 7f338e8..0000000 --- a/filter/filter.go +++ /dev/null @@ -1,10 +0,0 @@ -package filter - -import ( - "io" -) - -// Filter is used for filtering IP packets coming from TUN. -type Filter interface { - io.Writer -} diff --git a/filter/icmp.go b/filter/icmp.go deleted file mode 100644 index af7af95..0000000 --- a/filter/icmp.go +++ /dev/null @@ -1,32 +0,0 @@ -package filter - -import ( - "io" - - "github.com/xjasonlyu/tun2socks/common/packet" - "github.com/xjasonlyu/tun2socks/log" -) - -type icmpFilter struct { - writer io.Writer -} - -func NewICMPFilter(w io.Writer) Filter { - return &icmpFilter{writer: w} -} - -func (f *icmpFilter) Write(buf []byte) (int, error) { - switch buf[9] { - case packet.PROTOCOL_ICMP: - payload := make([]byte, len(buf)) - copy(payload, buf) - go func(data []byte) { - if _, err := f.writer.Write(data); err != nil { - log.Fatalf("failed to input data to the stack: %v", err) - } - }(payload) - return len(buf), nil - default: - return f.writer.Write(buf) - } -} diff --git a/go.mod b/go.mod deleted file mode 100644 index 1d2f205..0000000 --- a/go.mod +++ /dev/null @@ -1,15 +0,0 @@ -module github.com/xjasonlyu/tun2socks - -go 1.15 - -require ( - github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect - github.com/go-ole/go-ole v1.2.4 // indirect - github.com/gobuffalo/packr/v2 v2.8.0 - github.com/miekg/dns v1.1.31 - github.com/shirou/gopsutil v2.20.8+incompatible - github.com/sirupsen/logrus v1.6.0 - github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 - github.com/stretchr/testify v1.6.1 - golang.org/x/sys v0.0.0-20200918174421-af09f7315aff -) diff --git a/go.sum b/go.sum deleted file mode 100644 index 0a4ffe5..0000000 --- a/go.sum +++ /dev/null @@ -1,209 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= -github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= -github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gobuffalo/logger v1.0.3 h1:YaXOTHNPCvkqqA7w05A4v0k2tCdpr+sgFlgINbQ6gqc= -github.com/gobuffalo/logger v1.0.3/go.mod h1:SoeejUwldiS7ZsyCBphOGURmWdwUFXs0J7TCjEhjKxM= -github.com/gobuffalo/packd v1.0.0 h1:6ERZvJHfe24rfFmA9OaoKBdC7+c9sydrytMg8SdFGBM= -github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI= -github.com/gobuffalo/packr/v2 v2.8.0 h1:IULGd15bQL59ijXLxEvA5wlMxsmx/ZkQv9T282zNVIY= -github.com/gobuffalo/packr/v2 v2.8.0/go.mod h1:PDk2k3vGevNE3SwVyVRgQCCXETC9SaONCNSXT1Q8M1g= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/karrick/godirwalk v1.15.3 h1:0a2pXOgtB16CqIqXTiT7+K9L73f74n/aNQUnH6Ortew= -github.com/karrick/godirwalk v1.15.3/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= -github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= -github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= -github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= -github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= -github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= -github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= -github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo= -github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.5.2 h1:qLvObTrvO/XRCqmkKxUlOBc48bI3efyDuAZe25QiF0w= -github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shirou/gopsutil v2.20.8+incompatible h1:8c7Atn0FAUZJo+f4wYbN0iVpdWniCQk7IYwGtgdh1mY= -github.com/shirou/gopsutil v2.20.8+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8= -github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c h1:/nJuwDLoL/zrqY6gf57vxC+Pi+pZ8bfhpPkicO5H7W4= -golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200918174421-af09f7315aff h1:1CPUrky56AcgSpxz/KfgzQWzfG09u5YOL8MvPYBlrL8= -golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200308013534-11ec41452d41 h1:9Di9iYgOt9ThCipBxChBVhgNipDoE5mxO84rQV7D0FE= -golang.org/x/tools v0.0.0-20200308013534-11ec41452d41/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/load-tun.sh b/load-tun.sh deleted file mode 100644 index 457803f..0000000 --- a/load-tun.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -# Create the necessary file structure for /dev/net/tun -if ( [ ! -c /dev/net/tun ] ); then - if ( [ ! -d /dev/net ] ); then - mkdir -m 755 /dev/net - fi - mknod /dev/net/tun c 10 200 - chmod 0755 /dev/net/tun -fi - -# Load the tun module if not already loaded -if ( !(lsmod | grep -q "^tun\s") ); then - insmod /lib/modules/tun.ko -fi diff --git a/log/level.go b/log/level.go deleted file mode 100644 index cb80f49..0000000 --- a/log/level.go +++ /dev/null @@ -1,28 +0,0 @@ -package log - -const ( - DEBUG Level = iota - INFO - WARNING - ERROR - SILENT -) - -type Level int - -func (l Level) String() string { - switch l { - case INFO: - return "info" - case WARNING: - return "warning" - case ERROR: - return "error" - case DEBUG: - return "debug" - case SILENT: - return "silent" - default: - return "unknown" - } -} diff --git a/log/log.go b/log/log.go deleted file mode 100644 index 7694e65..0000000 --- a/log/log.go +++ /dev/null @@ -1,82 +0,0 @@ -package log - -import ( - "fmt" - "os" - - log "github.com/sirupsen/logrus" -) - -var ( - level = INFO -) - -func init() { - log.SetOutput(os.Stdout) - log.SetLevel(log.DebugLevel) -} - -type Event struct { - LogLevel Level - Payload string -} - -func (e *Event) Type() string { - return e.LogLevel.String() -} - -func Infof(format string, v ...interface{}) { - event := newLog(INFO, format, v...) - printf(event) -} - -func Warnf(format string, v ...interface{}) { - event := newLog(WARNING, format, v...) - printf(event) -} - -func Errorf(format string, v ...interface{}) { - event := newLog(ERROR, format, v...) - printf(event) -} - -func Debugf(format string, v ...interface{}) { - event := newLog(DEBUG, format, v...) - printf(event) -} - -func Fatalf(format string, v ...interface{}) { - log.Fatalf(format, v...) -} - -func Access(process, outbound, network, local, target string) { - Infof("[%v] [%v] [%v] %s --> %s", outbound, network, process, local, target) -} - -func SetLevel(newLevel Level) { - level = newLevel -} - -func printf(data *Event) { - if data.LogLevel < level { - return - } - - switch data.LogLevel { - case INFO: - log.Infoln(data.Payload) - case WARNING: - log.Warnln(data.Payload) - case ERROR: - log.Errorln(data.Payload) - case DEBUG: - log.Debugln(data.Payload) - } -} - -func newLog(logLevel Level, format string, v ...interface{}) *Event { - return &Event{ - LogLevel: logLevel, - Payload: fmt.Sprintf(format, v...), - } -} diff --git a/proxy/proxy.go b/proxy/proxy.go deleted file mode 100644 index 438fadd..0000000 --- a/proxy/proxy.go +++ /dev/null @@ -1,84 +0,0 @@ -package proxy - -import ( - "errors" - "net" - "strconv" - "strings" - - D "github.com/xjasonlyu/tun2socks/component/fakedns" - S "github.com/xjasonlyu/tun2socks/component/session" -) - -var ( - monitor S.Monitor - - fakeDNS D.FakeDNS - // default DNS address - hijackDNS []string -) - -func RegisterMonitor(m S.Monitor) { - monitor = m -} - -func RegisterFakeDNS(d D.FakeDNS, h string) { - fakeDNS = d - hijackDNS = append(hijackDNS, strings.Split(h, ",")...) -} - -// Session Operation -func addSession(key interface{}, session *S.Session) { - if monitor != nil { - monitor.AddSession(key, session) - } -} - -func removeSession(key interface{}) { - if monitor != nil { - monitor.RemoveSession(key) - } -} - -// Check target if is hijacked address. -func isHijacked(target *net.UDPAddr) bool { - if fakeDNS == nil { - // ignore when fake DNS disabled - return false - } - - for _, addr := range hijackDNS { - host, port, err := net.SplitHostPort(addr) - if err != nil { - continue - } - portInt, _ := strconv.Atoi(port) - if (host == "*" && portInt == target.Port) || addr == target.String() { - return true - } - } - return false -} - -// DNS lookup -func lookupHost(target net.Addr) (targetHost string, err error) { - var targetIP net.IP - switch addr := target.(type) { - case *net.TCPAddr: - targetIP = addr.IP - case *net.UDPAddr: - targetIP = addr.IP - default: - err = errors.New("invalid target type") - return - } - - targetHost = targetIP.String() - // Replace with a domain name if target address IP is a fake IP. - if fakeDNS != nil { - if host, exist := fakeDNS.IPToHost(targetIP); exist { - targetHost = host - } - } - return -} diff --git a/proxy/socks/socks.go b/proxy/socks/socks.go deleted file mode 100755 index f6aa70e..0000000 --- a/proxy/socks/socks.go +++ /dev/null @@ -1,247 +0,0 @@ -package socks - -import ( - "bytes" - "errors" - "io" - "net" - "strconv" -) - -const Version = 5 - -// Error represents a SOCKS error -type Error byte - -func (err Error) Error() string { - return "SOCKS5 error: " + strconv.Itoa(int(err)) -} - -// Command is request commands as defined in RFC 1928 section 4. -type Command = uint8 - -// SOCKS request commands as defined in RFC 1928 section 4. -const ( - CmdConnect Command = 1 - CmdBind Command = 2 - CmdUDPAssociate Command = 3 -) - -// SOCKS address types as defined in RFC 1928 section 5. -const ( - AtypIPv4 = 1 - AtypDomainName = 3 - AtypIPv6 = 4 -) - -// MaxAddrLen is the maximum size of SOCKS address in bytes. -const MaxAddrLen = 1 + 1 + 255 + 2 - -// MaxAuthLen is the maximum size of user/password field in SOCKS5 Auth -const MaxAuthLen = 255 - -// Addr represents a SOCKS address as defined in RFC 1928 section 5. -type Addr []byte - -func (a Addr) String() string { - var host, port string - - switch a[0] { - case AtypDomainName: - hostLen := uint16(a[1]) - host = string(a[2 : 2+hostLen]) - port = strconv.Itoa((int(a[2+hostLen]) << 8) | int(a[2+hostLen+1])) - case AtypIPv4: - host = net.IP(a[1 : 1+net.IPv4len]).String() - port = strconv.Itoa((int(a[1+net.IPv4len]) << 8) | int(a[1+net.IPv4len+1])) - case AtypIPv6: - host = net.IP(a[1 : 1+net.IPv6len]).String() - port = strconv.Itoa((int(a[1+net.IPv6len]) << 8) | int(a[1+net.IPv6len+1])) - } - - return net.JoinHostPort(host, port) -} - -// SOCKS errors as defined in RFC 1928 section 6. -const ( - ErrGeneralFailure = Error(1) - ErrConnectionNotAllowed = Error(2) - ErrNetworkUnreachable = Error(3) - ErrHostUnreachable = Error(4) - ErrConnectionRefused = Error(5) - ErrTTLExpired = Error(6) - ErrCommandNotSupported = Error(7) - ErrAddressNotSupported = Error(8) -) - -// Auth errors used to return a specific "Auth failed" error -var ErrAuth = errors.New("auth failed") - -// ClientHandshake fast-tracks SOCKS initialization to get target address to connect on client side. -func ClientHandshake(rw io.ReadWriter, addr Addr, command Command) (Addr, error) { - buf := make([]byte, MaxAddrLen) - var err error - - // VER, NMETHODS, METHODS - _, err = rw.Write([]byte{Version, 1, 0}) - - if err != nil { - return nil, err - } - - // VER, METHOD - if _, err := io.ReadFull(rw, buf[:2]); err != nil { - return nil, err - } - - if buf[0] != 5 { - return nil, errors.New("SOCKS version error") - } - - if buf[1] != 0 { - return nil, errors.New("SOCKS need auth") - } - - // VER, CMD, RSV, ADDR - if _, err := rw.Write(bytes.Join([][]byte{{5, command, 0}, addr}, []byte{})); err != nil { - return nil, err - } - - // VER, REP, RSV - if _, err := io.ReadFull(rw, buf[:3]); err != nil { - return nil, err - } - - return readAddr(rw, buf) -} - -func readAddr(r io.Reader, b []byte) (Addr, error) { - if len(b) < MaxAddrLen { - return nil, io.ErrShortBuffer - } - _, err := io.ReadFull(r, b[:1]) // read 1st byte for address type - if err != nil { - return nil, err - } - - switch b[0] { - case AtypDomainName: - _, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length - if err != nil { - return nil, err - } - domainLength := uint16(b[1]) - _, err = io.ReadFull(r, b[2:2+domainLength+2]) - return b[:1+1+domainLength+2], err - case AtypIPv4: - _, err = io.ReadFull(r, b[1:1+net.IPv4len+2]) - return b[:1+net.IPv4len+2], err - case AtypIPv6: - _, err = io.ReadFull(r, b[1:1+net.IPv6len+2]) - return b[:1+net.IPv6len+2], err - } - - return nil, ErrAddressNotSupported -} - -// SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed. -func SplitAddr(b []byte) Addr { - addrLen := 1 - if len(b) < addrLen { - return nil - } - - switch b[0] { - case AtypDomainName: - if len(b) < 2 { - return nil - } - addrLen = 1 + 1 + int(b[1]) + 2 - case AtypIPv4: - addrLen = 1 + net.IPv4len + 2 - case AtypIPv6: - addrLen = 1 + net.IPv6len + 2 - default: - return nil - - } - - if len(b) < addrLen { - return nil - } - - return b[:addrLen] -} - -// ParseAddr parses the address in string s. Returns nil if failed. -func ParseAddr(s string) Addr { - var addr Addr - host, port, err := net.SplitHostPort(s) - if err != nil { - return nil - } - if ip := net.ParseIP(host); ip != nil { - if ip4 := ip.To4(); ip4 != nil { - addr = make([]byte, 1+net.IPv4len+2) - addr[0] = AtypIPv4 - copy(addr[1:], ip4) - } else { - addr = make([]byte, 1+net.IPv6len+2) - addr[0] = AtypIPv6 - copy(addr[1:], ip) - } - } else { - if len(host) > 255 { - return nil - } - addr = make([]byte, 1+1+len(host)+2) - addr[0] = AtypDomainName - addr[1] = byte(len(host)) - copy(addr[2:], host) - } - - portUint, err := strconv.ParseUint(port, 10, 16) - if err != nil { - return nil - } - - addr[len(addr)-2], addr[len(addr)-1] = byte(portUint>>8), byte(portUint) - - return addr -} - -func DecodeUDPPacket(packet []byte) (addr Addr, payload []byte, err error) { - if len(packet) < 5 { - err = errors.New("insufficient length of packet") - return - } - - // packet[0] and packet[1] are reserved - if !bytes.Equal(packet[:2], []byte{0, 0}) { - err = errors.New("reserved fields should be zero") - return - } - - if packet[2] != 0 /* fragments */ { - err = errors.New("discarding fragmented payload") - return - } - - addr = SplitAddr(packet[3:]) - if addr == nil { - err = errors.New("failed to read UDP header") - } - - payload = make([]byte, len(packet[3+len(addr):])) - copy(payload, packet[3+len(addr):]) - return -} - -func EncodeUDPPacket(addr Addr, payload []byte) (packet []byte, err error) { - if addr == nil { - err = errors.New("address is invalid") - return - } - packet = bytes.Join([][]byte{{0, 0, 0}, addr, payload}, []byte{}) - return -} diff --git a/proxy/tcp.go b/proxy/tcp.go deleted file mode 100644 index ad0ff1d..0000000 --- a/proxy/tcp.go +++ /dev/null @@ -1,126 +0,0 @@ -package proxy - -import ( - "io" - "net" - "strconv" - "sync" - "time" - - "github.com/xjasonlyu/tun2socks/common/lsof" - "github.com/xjasonlyu/tun2socks/common/pool" - "github.com/xjasonlyu/tun2socks/core" - "github.com/xjasonlyu/tun2socks/log" - - S "github.com/xjasonlyu/tun2socks/component/session" -) - -type tcpHandler struct { - proxyHost string - proxyPort int -} - -func NewTCPHandler(proxyHost string, proxyPort int) core.TCPConnHandler { - return &tcpHandler{ - proxyHost: proxyHost, - proxyPort: proxyPort, - } -} - -func (h *tcpHandler) relay(localConn, remoteConn net.Conn) { - var once sync.Once - closeOnce := func() { - once.Do(func() { - localConn.Close() - remoteConn.Close() - }) - } - - // Cleanup - defer func() { - // Close - closeOnce() - // Remove session - removeSession(localConn) - }() - - // WaitGroup - var wg sync.WaitGroup - wg.Add(1) - - // Up Link - go func() { - buf := pool.BufPool.Get().([]byte) - defer pool.BufPool.Put(buf[:cap(buf)]) - if _, err := io.CopyBuffer(remoteConn, localConn, buf); err != nil { - closeOnce() - } else { - localConn.SetDeadline(time.Now()) - remoteConn.SetDeadline(time.Now()) - tcpCloseRead(remoteConn) - } - wg.Done() - }() - - // Down Link - buf := pool.BufPool.Get().([]byte) - if _, err := io.CopyBuffer(localConn, remoteConn, buf); err != nil { - closeOnce() - } else { - localConn.SetDeadline(time.Now()) - remoteConn.SetDeadline(time.Now()) - tcpCloseRead(localConn) - } - pool.BufPool.Put(buf[:cap(buf)]) - - wg.Wait() // Wait for Up Link done -} - -func (h *tcpHandler) Handle(conn net.Conn, target *net.TCPAddr) error { - // Alias - var localConn = conn - - // Lookup fakeDNS host record - targetHost, err := lookupHost(target) - if err != nil { - log.Warnf("lookup target host: %v", err) - return err - } - - proxyAddr := net.JoinHostPort(h.proxyHost, strconv.Itoa(h.proxyPort)) - targetAddr := net.JoinHostPort(targetHost, strconv.Itoa(target.Port)) - // Dial - remoteConn, err := dial(proxyAddr, targetAddr) - if err != nil { - log.Infof("Dial: %v", err) - return err - } - - var process = "N/A" - if monitor != nil { - // Get name of the process - process = lsof.GetProcessName(localConn.LocalAddr()) - session := &S.Session{ - Process: process, - Network: localConn.LocalAddr().Network(), - DialerAddr: remoteConn.LocalAddr().String(), - ClientAddr: localConn.LocalAddr().String(), - TargetAddr: targetAddr, - UploadBytes: 0, - DownloadBytes: 0, - SessionStart: time.Now(), - } - addSession(localConn, session) - remoteConn = &S.Conn{Session: session, Conn: remoteConn} - } - - // Set keepalive - tcpKeepAlive(localConn) - tcpKeepAlive(remoteConn) - - // Relay connections - go h.relay(localConn, remoteConn) - - log.Access(process, "proxy", "tcp", localConn.LocalAddr().String(), targetAddr) - return nil -} diff --git a/proxy/udp.go b/proxy/udp.go deleted file mode 100644 index 705c538..0000000 --- a/proxy/udp.go +++ /dev/null @@ -1,165 +0,0 @@ -package proxy - -import ( - "fmt" - "net" - "strconv" - "sync" - "time" - - "github.com/xjasonlyu/tun2socks/common/lsof" - "github.com/xjasonlyu/tun2socks/common/pool" - "github.com/xjasonlyu/tun2socks/core" - "github.com/xjasonlyu/tun2socks/log" - - S "github.com/xjasonlyu/tun2socks/component/session" -) - -type udpHandler struct { - proxyHost string - proxyPort int - timeout time.Duration - - remoteMap sync.Map -} - -func NewUDPHandler(proxyHost string, proxyPort int, timeout time.Duration) core.UDPConnHandler { - return &udpHandler{ - proxyHost: proxyHost, - proxyPort: proxyPort, - timeout: timeout, - } -} - -func (h *udpHandler) fetchUDPInput(conn core.UDPConn, input net.PacketConn, addr *net.UDPAddr) { - buf := pool.BufPool.Get().([]byte) - - defer func() { - h.Close(conn) - pool.BufPool.Put(buf[:cap(buf)]) - }() - - for { - input.SetDeadline(time.Now().Add(h.timeout)) - n, _, err := input.ReadFrom(buf) - if err != nil { - if !isTimeout(err) && !isClosed(err) { - log.Warnf("failed to read UDP data from remote: %v", err) - } - return - } - - if _, err := conn.WriteFrom(buf[:n], addr); err != nil { - log.Warnf("failed to write UDP data: %v", err) - return - } - } -} - -func (h *udpHandler) Connect(conn core.UDPConn, target *net.UDPAddr) error { - // Check hijackDNS - if isHijacked(target) { - return nil - } - - // Lookup fakeDNS host record - targetHost, err := lookupHost(target) - if err != nil { - log.Warnf("lookup target host: %v", err) - return err - } - - proxyAddr := net.JoinHostPort(h.proxyHost, strconv.Itoa(h.proxyPort)) - targetAddr := net.JoinHostPort(targetHost, strconv.Itoa(target.Port)) - // Dial - remoteConn, remoteAddr, err := dialUDP(proxyAddr, targetAddr) - if err != nil { - log.Infof("DialUDP: %v", err) - return err - } - - var process = "N/A" - if monitor != nil { - // Get name of the process - process = lsof.GetProcessName(conn.LocalAddr()) - session := &S.Session{ - Process: process, - Network: conn.LocalAddr().Network(), - DialerAddr: remoteConn.LocalAddr().String(), - ClientAddr: conn.LocalAddr().String(), - TargetAddr: targetAddr, - UploadBytes: 0, - DownloadBytes: 0, - SessionStart: time.Now(), - } - addSession(conn, session) - remoteConn = &S.PacketConn{Session: session, PacketConn: remoteConn} - } - - h.remoteMap.Store(conn, &udpElement{ - remoteAddr: remoteAddr, - remoteConn: remoteConn, - }) - - go h.fetchUDPInput(conn, remoteConn, target) - - log.Access(process, "proxy", "udp", conn.LocalAddr().String(), targetAddr) - return nil -} - -func (h *udpHandler) ReceiveTo(conn core.UDPConn, data []byte, addr *net.UDPAddr) (err error) { - // Close if return error - defer func() { - if err != nil { - h.Close(conn) - } - }() - - // Check hijackDNS - if isHijacked(addr) { - resp, err := fakeDNS.Resolve(data) - if err != nil { - return fmt.Errorf("hijack DNS request error: %v", err) - } - - if _, err = conn.WriteFrom(resp, addr); err != nil { - return fmt.Errorf("write dns answer failed: %v", err) - } - h.Close(conn) - return nil - } - - var remoteAddr net.Addr - var remoteConn net.PacketConn - - if elm, ok := h.remoteMap.Load(conn); ok { - remoteAddr = elm.(*udpElement).remoteAddr - remoteConn = elm.(*udpElement).remoteConn - } - - if remoteAddr == nil || remoteConn == nil { - return fmt.Errorf("proxy connection %v->%v does not exists", conn.LocalAddr(), addr) - } - - if _, err = remoteConn.WriteTo(data, remoteAddr); err != nil { - return fmt.Errorf("write remote failed: %v", err) - } - - return nil -} - -func (h *udpHandler) Close(conn core.UDPConn) { - // Close - conn.Close() - - // Load from remoteConnMap - if elm, ok := h.remoteMap.Load(conn); ok { - elm.(*udpElement).remoteConn.Close() - h.remoteMap.Delete(conn) - } else { - return - } - - // Remove session - removeSession(conn) -} diff --git a/proxy/utils.go b/proxy/utils.go deleted file mode 100644 index 34a6b5e..0000000 --- a/proxy/utils.go +++ /dev/null @@ -1,157 +0,0 @@ -package proxy - -import ( - "fmt" - "io" - "io/ioutil" - "net" - "strings" - "time" - - "github.com/xjasonlyu/tun2socks/proxy/socks" -) - -// Error -func isTimeout(err error) bool { - if netErr, ok := err.(net.Error); ok { - return netErr.Timeout() - } - return false -} - -func isClosed(err error) bool { - want := "use of closed network connection" - return strings.Contains(err.Error(), want) -} - -// UDP util -type udpElement struct { - remoteAddr net.Addr - remoteConn net.PacketConn -} - -// TCP functions -type duplexConn interface { - net.Conn - CloseRead() error - CloseWrite() error -} - -func tcpCloseRead(conn net.Conn) { - if c, ok := conn.(duplexConn); ok { - c.CloseRead() - } -} - -func tcpCloseWrite(conn net.Conn) { - if c, ok := conn.(duplexConn); ok { - c.CloseWrite() - } -} - -func tcpKeepAlive(conn net.Conn) { - if tcp, ok := conn.(*net.TCPConn); ok { - tcp.SetKeepAlive(true) - tcp.SetKeepAlivePeriod(30 * time.Second) - } -} - -// Socks dialer -func dial(proxy, target string) (net.Conn, error) { - c, err := net.DialTimeout("tcp", proxy, 5*time.Second) - if err != nil { - return nil, fmt.Errorf("%s connect error", proxy) - } - - targetAddr := socks.ParseAddr(target) - if targetAddr == nil { - return nil, fmt.Errorf("target address parse error") - } - - if _, err := socks.ClientHandshake(c, targetAddr, socks.CmdConnect); err != nil { - return nil, err - } - return c, nil -} - -func dialUDP(proxy, target string) (_ net.PacketConn, _ net.Addr, err error) { - c, err := net.DialTimeout("tcp", proxy, 5*time.Second) - if err != nil { - err = fmt.Errorf("%s connect error", proxy) - return - } - - // tcp set keepalive - tcpKeepAlive(c) - - defer func() { - if err != nil { - c.Close() - } - }() - - targetAddr := socks.ParseAddr(target) - if targetAddr == nil { - err = fmt.Errorf("target address parse error") - return - } - - bindAddr, err := socks.ClientHandshake(c, targetAddr, socks.CmdUDPAssociate) - if err != nil { - err = fmt.Errorf("%v client hanshake error", err) - return - } - - addr, err := net.ResolveUDPAddr("udp", bindAddr.String()) - if err != nil { - return - } - - pc, err := net.ListenPacket("udp", "") - if err != nil { - return - } - - go func() { - io.Copy(ioutil.Discard, c) - c.Close() - // A UDP association terminates when the TCP connection that the UDP - // ASSOCIATE request arrived on terminates. RFC1928 - pc.Close() - }() - - return &socksUDPConn{PacketConn: pc, tcpConn: c, targetAddr: targetAddr}, addr, nil -} - -// Socks wrapped UDPConn -type socksUDPConn struct { - net.PacketConn - tcpConn net.Conn - targetAddr socks.Addr -} - -func (c *socksUDPConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { - packet, err := socks.EncodeUDPPacket(c.targetAddr, b) - if err != nil { - return - } - return c.PacketConn.WriteTo(packet, addr) -} - -func (c *socksUDPConn) ReadFrom(b []byte) (int, net.Addr, error) { - n, a, e := c.PacketConn.ReadFrom(b) - if e != nil { - return 0, nil, e - } - addr, payload, err := socks.DecodeUDPPacket(b) - if err != nil { - return 0, nil, err - } - copy(b, payload) - return n - len(addr) - 3, a, nil -} - -func (c *socksUDPConn) Close() error { - c.tcpConn.Close() - return c.PacketConn.Close() -} diff --git a/screenshot.png b/screenshot.png deleted file mode 100644 index 1e6541f186d2308c8a746c92843e1255bff24fe3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1061953 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

H0>YPM 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≪y8|)A-3y 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�#Jb!}L{0SiTn6e$5hbEHTM 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
V#K4A`c|qE;rfuCKTS)r=;L@{gD7wMqp2 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%0D$laAqWj7|+1T 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≷4}|4L5W-!e#|z5 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

e<$x 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
STXJGpg6AWfQ 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

?Pt7N*R6bMGf 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 diff --git a/tun/README.md b/tun/README.md deleted file mode 100644 index 9265c0d..0000000 --- a/tun/README.md +++ /dev/null @@ -1 +0,0 @@ -Files in this directory are copied from https://github.com/yinghuocho/gotun2socks, with slightly modifies. diff --git a/tun/stop.go b/tun/stop.go deleted file mode 100644 index 073ffe2..0000000 --- a/tun/stop.go +++ /dev/null @@ -1,34 +0,0 @@ -package tun - -import ( - "bytes" - "log" - "net" -) - -var stopMarker = []byte{2, 2, 2, 2, 2, 2, 2, 2} - -// Close of Windows and Linux tun/tap device do not interrupt blocking Read. -// sendStopMarker is used to issue a specific packet to notify threads blocking -// on Read. -func sendStopMarker(src, dst string) { - l, _ := net.ResolveUDPAddr("udp", src+":2222") - r, _ := net.ResolveUDPAddr("udp", dst+":2222") - conn, err := net.DialUDP("udp", l, r) - if err != nil { - log.Printf("fail to send stopmarker: %s", err) - return - } - defer conn.Close() - conn.Write(stopMarker) -} - -func isStopMarker(pkt []byte, src, dst net.IP) bool { - n := len(pkt) - // at least should be 20(ip) + 8(udp) + 8(stopmarker) - if n < 20+8+8 { - return false - } - return pkt[0]&0xf0 == 0x40 && pkt[9] == 0x11 && src.Equal(pkt[12:16]) && - dst.Equal(pkt[16:20]) && bytes.Compare(pkt[n-8:n], stopMarker) == 0 -} diff --git a/tun/tun_darwin.go b/tun/tun_darwin.go deleted file mode 100644 index 2a9827b..0000000 --- a/tun/tun_darwin.go +++ /dev/null @@ -1,68 +0,0 @@ -package tun - -import ( - "errors" - "fmt" - "io" - "net" - "os/exec" - "strconv" - "strings" - - "github.com/songgao/water" -) - -func isIPv4(ip net.IP) bool { - if ip.To4() != nil { - return true - } - return false -} - -func isIPv6(ip net.IP) bool { - // To16() also valid for ipv4, ensure it's not an ipv4 address - if ip.To4() != nil { - return false - } - if ip.To16() != nil { - return true - } - return false -} - -func OpenTunDevice(name, addr, gw, mask string, dnsServers []string, persist bool) (io.ReadWriteCloser, error) { - _ = dnsServers - tunDev, err := water.New(water.Config{ - DeviceType: water.TUN, - }) - if err != nil { - return nil, err - } - name = tunDev.Name() - ip := net.ParseIP(addr) - if ip == nil { - return nil, errors.New("invalid IP address") - } - - var params string - if isIPv4(ip) { - params = fmt.Sprintf("%s inet %s netmask %s %s", name, addr, mask, gw) - } else if isIPv6(ip) { - prefixLen, err := strconv.Atoi(mask) - if err != nil { - return nil, errors.New(fmt.Sprintf("parse IPv6 prefixlen failed: %v", err)) - } - params = fmt.Sprintf("%s inet6 %s/%d", name, addr, prefixLen) - } else { - return nil, errors.New("invalid IP address") - } - - out, err := exec.Command("ifconfig", strings.Split(params, " ")...).Output() - if err != nil { - if len(out) != 0 { - return nil, errors.New(fmt.Sprintf("%v, output: %s", err, out)) - } - return nil, err - } - return tunDev, nil -} diff --git a/tun/tun_linux.go b/tun/tun_linux.go deleted file mode 100644 index 9154395..0000000 --- a/tun/tun_linux.go +++ /dev/null @@ -1,27 +0,0 @@ -package tun - -import ( - "errors" - "io" - "net" - - "github.com/songgao/water" -) - -func OpenTunDevice(name, addr, gw, mask string, dnsServers []string, persist bool) (io.ReadWriteCloser, error) { - cfg := water.Config{ - DeviceType: water.TUN, - } - cfg.Name = name - cfg.Persist = persist - tunDev, err := water.New(cfg) - if err != nil { - return nil, err - } - name = tunDev.Name() - ip := net.ParseIP(addr) - if ip == nil { - return nil, errors.New("invalid IP address") - } - return tunDev, nil -} diff --git a/tun/tun_windows.go b/tun/tun_windows.go deleted file mode 100644 index 97d640b..0000000 --- a/tun/tun_windows.go +++ /dev/null @@ -1,391 +0,0 @@ -package tun - -import ( - "encoding/binary" - // "encoding/hex" - "errors" - "fmt" - "io" - "log" - "net" - "os/exec" - "strings" - "sync" - "syscall" - "unsafe" - - "golang.org/x/sys/windows" - "golang.org/x/sys/windows/registry" -) - -const ( - TAPWIN32_MAX_REG_SIZE = 256 - TUNTAP_COMPONENT_ID_0901 = "tap0901" - TUNTAP_COMPONENT_ID_0801 = "tap0801" - NETWORK_KEY = `SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}` - ADAPTER_KEY = `SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}` -) - -func ctl_code(device_type, function, method, access uint32) uint32 { - return (device_type << 16) | (access << 14) | (function << 2) | method -} - -func tap_control_code(request, method uint32) uint32 { - return ctl_code(34, request, method, 0) -} - -var ( - k32 = windows.NewLazySystemDLL("kernel32.dll") - procGetOverlappedResult = k32.NewProc("GetOverlappedResult") - TAP_IOCTL_GET_MTU = tap_control_code(3, 0) - TAP_IOCTL_SET_MEDIA_STATUS = tap_control_code(6, 0) - TAP_IOCTL_CONFIG_TUN = tap_control_code(10, 0) - TAP_WIN_IOCTL_CONFIG_DHCP_MASQ = tap_control_code(7, 0) - TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT = tap_control_code(9, 0) -) - -func decodeUTF16(b []byte) string { - if len(b)%2 != 0 { - return "" - } - - l := len(b) / 2 - u16 := make([]uint16, l) - for i := 0; i < l; i += 1 { - u16[i] = uint16(b[2*i]) + (uint16(b[2*i+1]) << 8) - } - return windows.UTF16ToString(u16) -} - -func getTuntapName(componentId string) (string, error) { - keyName := fmt.Sprintf(NETWORK_KEY+"\\%s\\Connection", componentId) - key, err := registry.OpenKey(registry.LOCAL_MACHINE, keyName, registry.READ) - if err != nil { - key.Close() - return "", err - } - var bufLength uint32 = TAPWIN32_MAX_REG_SIZE - buf := make([]byte, bufLength) - name, _ := windows.UTF16FromString("Name") - var valtype uint32 - err = windows.RegQueryValueEx( - windows.Handle(key), - &name[0], - nil, - &valtype, - &buf[0], - &bufLength, - ) - if err != nil { - key.Close() - return "", err - } - s := decodeUTF16(buf) - return s, nil -} - -func getTuntapComponentId(ifaceName string) (string, string, error) { - adapters, err := registry.OpenKey(registry.LOCAL_MACHINE, ADAPTER_KEY, registry.READ) - if err != nil { - return "", "", fmt.Errorf("failed to read adapter list: %v", err) - } - defer adapters.Close() - var i uint32 - for i = 0; i < 1000; i++ { - var name_length uint32 = TAPWIN32_MAX_REG_SIZE - buf := make([]uint16, name_length) - if err = windows.RegEnumKeyEx( - windows.Handle(adapters), - i, - &buf[0], - &name_length, - nil, - nil, - nil, - nil); err != nil { - return "", "", fmt.Errorf("failed to read name: %v", err) - } - key_name := windows.UTF16ToString(buf[:]) - adapter, err := registry.OpenKey(adapters, key_name, registry.READ) - defer adapter.Close() - if err != nil { - continue - } - name, _ := windows.UTF16FromString("ComponentId") - name2, _ := windows.UTF16FromString("NetCfgInstanceId") - var valtype uint32 - var component_id = make([]byte, TAPWIN32_MAX_REG_SIZE) - var componentLen = uint32(len(component_id)) - if err = windows.RegQueryValueEx( - windows.Handle(adapter), - &name[0], - nil, - &valtype, - &component_id[0], - &componentLen); err != nil { - continue - } - - id := decodeUTF16(component_id) - if id == TUNTAP_COMPONENT_ID_0901 || id == TUNTAP_COMPONENT_ID_0801 { - var valtype uint32 - var netCfgInstanceId = make([]byte, TAPWIN32_MAX_REG_SIZE) - var netCfgInstanceIdLen = uint32(len(netCfgInstanceId)) - if err = windows.RegQueryValueEx( - windows.Handle(adapter), - &name2[0], - nil, - &valtype, - &netCfgInstanceId[0], - &netCfgInstanceIdLen); err != nil { - return "", "", fmt.Errorf("failed to read net cfg instance id: %v", err) - } - s := decodeUTF16(netCfgInstanceId) - log.Printf("TAP device component ID: %s", s) - - devName, err := getTuntapName(s) - if err != nil { - return "", "", fmt.Errorf("failed to get tun/tap name: %v", err) - } - if len(ifaceName) == 0 { - return s, devName, nil - } else if devName == ifaceName { - return s, devName, nil - } - } - } - return "", "", errors.New("not found component id") -} - -func OpenTunDevice(name, addr, gw, mask string, dns []string, persist bool) (io.ReadWriteCloser, error) { - componentId, devName, err := getTuntapComponentId(name) - if err != nil { - return nil, fmt.Errorf("failed to get component ID: %v", err) - } - log.Printf("TAP device name: %s", devName) - - devId, _ := windows.UTF16FromString(fmt.Sprintf(`\\.\Global\%s.tap`, componentId)) - // set dhcp with netsh - cmd := exec.Command("netsh", "interface", "ip", "set", "address", devName, "dhcp") - cmd.Run() - cmd = exec.Command("netsh", "interface", "ip", "set", "dns", devName, "dhcp") - cmd.Run() - // open - fd, err := windows.CreateFile( - &devId[0], - windows.GENERIC_READ|windows.GENERIC_WRITE, - windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, - nil, - windows.OPEN_EXISTING, - windows.FILE_ATTRIBUTE_SYSTEM|windows.FILE_FLAG_OVERLAPPED, - //windows.FILE_ATTRIBUTE_SYSTEM, - 0, - ) - if err != nil { - return nil, err - } - // set addresses with dhcp - var returnLen uint32 - tunAddr := net.ParseIP(addr).To4() - tunMask := net.ParseIP(mask).To4() - gwAddr := net.ParseIP(gw).To4() - addrParam := append(tunAddr, tunMask...) - addrParam = append(addrParam, gwAddr...) - lease := make([]byte, 4) - binary.BigEndian.PutUint32(lease[:], 86400) - addrParam = append(addrParam, lease...) - err = windows.DeviceIoControl( - fd, - TAP_WIN_IOCTL_CONFIG_DHCP_MASQ, - &addrParam[0], - uint32(len(addrParam)), - &addrParam[0], - uint32(len(addrParam)), - &returnLen, - nil, - ) - if err != nil { - windows.Close(fd) - return nil, err - } else { - log.Printf("Set %s with net/mask: %s/%s through DHCP", devName, addr, mask) - } - - // set dns with dncp - dnsParam := []byte{6, 4} - primaryDNS := net.ParseIP(dns[0]).To4() - dnsParam = append(dnsParam, primaryDNS...) - if len(dns) >= 2 { - secondaryDNS := net.ParseIP(dns[1]).To4() - dnsParam = append(dnsParam, secondaryDNS...) - dnsParam[1] += 4 - } - err = windows.DeviceIoControl( - fd, - TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT, - &dnsParam[0], - uint32(len(dnsParam)), - &addrParam[0], - uint32(len(dnsParam)), - &returnLen, - nil, - ) - if err != nil { - windows.Close(fd) - return nil, err - } else { - log.Printf("Set %s with DNS: %s through DHCP", devName, strings.Join(dns, ",")) - } - - // set connect. - inBuffer := []byte("\x01\x00\x00\x00") - err = windows.DeviceIoControl( - fd, - TAP_IOCTL_SET_MEDIA_STATUS, - &inBuffer[0], - uint32(len(inBuffer)), - &inBuffer[0], - uint32(len(inBuffer)), - &returnLen, - nil, - ) - if err != nil { - windows.Close(fd) - return nil, err - } - return newWinTapDev(fd, addr, gw), nil -} - -type winTapDev struct { - // TODO Not sure if a read lock is needed. - readLock sync.Mutex - // Write is not allowed concurrent accessing. - writeLock sync.Mutex - - fd windows.Handle - addr string - addrIP net.IP - gw string - gwIP net.IP - rBuf [2048]byte - wBuf [2048]byte - wInitiated bool - rOverlapped windows.Overlapped - wOverlapped windows.Overlapped -} - -func newWinTapDev(fd windows.Handle, addr string, gw string) *winTapDev { - rOverlapped := windows.Overlapped{} - rEvent, _ := windows.CreateEvent(nil, 0, 0, nil) - rOverlapped.HEvent = windows.Handle(rEvent) - - wOverlapped := windows.Overlapped{} - wEvent, _ := windows.CreateEvent(nil, 0, 0, nil) - wOverlapped.HEvent = windows.Handle(wEvent) - - dev := &winTapDev{ - fd: fd, - rOverlapped: rOverlapped, - wOverlapped: wOverlapped, - wInitiated: false, - - addr: addr, - addrIP: net.ParseIP(addr).To4(), - gw: gw, - gwIP: net.ParseIP(gw).To4(), - } - return dev -} - -func (dev *winTapDev) Read(data []byte) (int, error) { - dev.readLock.Lock() - defer dev.readLock.Unlock() - - for { - var done uint32 - var nr int - - err := windows.ReadFile(dev.fd, dev.rBuf[:], &done, &dev.rOverlapped) - if err != nil { - if err != windows.ERROR_IO_PENDING { - return 0, err - } else { - windows.WaitForSingleObject(dev.rOverlapped.HEvent, windows.INFINITE) - nr, err = getOverlappedResult(dev.fd, &dev.rOverlapped) - if err != nil { - return 0, err - } - } - } else { - nr = int(done) - } - if nr > 14 { - if isStopMarker(dev.rBuf[14:nr], dev.addrIP, dev.gwIP) { - return 0, errors.New("received stop marker") - } - - // discard IPv6 packets - if dev.rBuf[14]&0xf0 == 0x60 { - continue - } else if dev.rBuf[14]&0xf0 == 0x40 { - if !dev.wInitiated { - // copy ether header for writing - copy(dev.wBuf[:], dev.rBuf[6:12]) - copy(dev.wBuf[6:], dev.rBuf[0:6]) - copy(dev.wBuf[12:], dev.rBuf[12:14]) - dev.wInitiated = true - } - copy(data, dev.rBuf[14:nr]) - return nr - 14, nil - } - } - } -} - -func (dev *winTapDev) Write(data []byte) (int, error) { - dev.writeLock.Lock() - defer dev.writeLock.Unlock() - - var done uint32 - var nw int - - payloadL := copy(dev.wBuf[14:], data) - packetL := payloadL + 14 - err := windows.WriteFile(dev.fd, dev.wBuf[:packetL], &done, &dev.wOverlapped) - if err != nil { - if err != windows.ERROR_IO_PENDING { - return 0, err - } else { - windows.WaitForSingleObject(dev.wOverlapped.HEvent, windows.INFINITE) - nw, err = getOverlappedResult(dev.fd, &dev.wOverlapped) - if err != nil { - return 0, err - } - } - } else { - nw = int(done) - } - if nw != packetL { - return 0, fmt.Errorf("write %d packet (%d bytes payload), return %d", packetL, payloadL, nw) - } else { - return payloadL, nil - } -} - -func getOverlappedResult(h windows.Handle, overlapped *windows.Overlapped) (int, error) { - var n int - r, _, err := syscall.Syscall6(procGetOverlappedResult.Addr(), 4, - uintptr(h), - uintptr(unsafe.Pointer(overlapped)), - uintptr(unsafe.Pointer(&n)), 1, 0, 0) - if r == 0 { - return n, err - } - return n, nil -} - -func (dev *winTapDev) Close() error { - log.Printf("close winTap device") - sendStopMarker(dev.addr, dev.gw) - return windows.Close(dev.fd) -}

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%0ADhgYWjXnMk@? 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